Merge remote-tracking branch 'isle/master'
Some checks are pending
CI / clang-format (push) Waiting to run
CI / ${{ matrix.name }} (false, --toolchain /usr/local/vitasdk/share/vita.toolchain.cmake, false, false, Ninja, Vita, ubuntu-latest, true, true) (push) Waiting to run
CI / ${{ matrix.name }} (false, -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.26100.0, false, false, Visual Studio 17 2022, true, Xbox One, windows-latest, amd64, false, true) (push) Waiting to run
CI / ${{ matrix.name }} (false, -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/3DS.cmake, false, devkitpro/devkitarm:latest, false, Ninja, true, Nintendo 3DS, ubuntu-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (false, -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake, false, devkitpro/devkita64:latest, false, Ninja, Nintendo Switch, true, ubuntu-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (false, emcmake, false, false, true, Ninja, Emscripten, ubuntu-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (false, false, false, Ninja, true, MSVC (arm64), windows-latest, amd64_arm64, false) (push) Waiting to run
CI / ${{ matrix.name }} (false, false, true, Ninja, true, MSVC (x86), windows-latest, amd64_x86, false) (push) Waiting to run
CI / ${{ matrix.name }} (false, true, false, Ninja, true, MSVC (x64), windows-latest, amd64, false) (push) Waiting to run
CI / ${{ matrix.name }} (false, true, true, false, Ninja, true, MSVC (x64 Debug), windows-latest, amd64, false) (push) Waiting to run
CI / ${{ matrix.name }} (true, false, -DCMAKE_SYSTEM_NAME=iOS, false, false, Xcode, true, iOS, macos-15, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, false, false, Ninja, true, mingw-w64-i686, mingw32, msys2 mingw32, windows-latest, msys2 {0}, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, false, false, false, Ninja, Android, ubuntu-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, false, true, false, Ninja, macOS, macos-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, true, false, Ninja, true, mingw-w64-x86_64, mingw64, msys2 mingw64, windows-latest, msys2 {0}, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, true, true, false, Ninja, true, Linux (Debug), ubuntu-latest, true) (push) Waiting to run
CI / ${{ matrix.name }} (true, true, true, false, Ninja, true, Linux, ubuntu-latest, true) (push) Waiting to run
CI / Flatpak (${{ matrix.arch }}) (aarch64, ubuntu-22.04-arm) (push) Waiting to run
CI / Flatpak (${{ matrix.arch }}) (x86_64, ubuntu-latest) (push) Waiting to run
CI / C++ (push) Waiting to run
CI / Release (push) Blocked by required conditions
Docker / Publish web port (push) Waiting to run

This commit is contained in:
Christian Semmler 2026-01-30 17:05:27 -08:00
commit a3122cd209
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
87 changed files with 3268 additions and 2278 deletions

635
.pylintrc
View File

@ -1,635 +0,0 @@
[MAIN]
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Clear in-memory caches upon conclusion of linting. Useful if running pylint
# in a server-like mode.
clear-cache-post-run=no
# Load and enable all available extensions. Use --list-extensions to see a list
# all available extensions.
#enable-all-extensions=
# In error mode, messages with a category besides ERROR or FATAL are
# suppressed, and no reports are done by default. Error mode is compatible with
# disabling specific errors.
#errors-only=
# Always return a 0 (non-error) status code, even if lint errors are found.
# This is primarily useful in continuous integration scripts.
#exit-zero=
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-allow-list=
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
# for backward compatibility.)
extension-pkg-whitelist=
# Return non-zero exit code if any of these messages/categories are detected,
# even if score is above --fail-under value. Syntax same as enable. Messages
# specified are enabled, while categories only check already-enabled messages.
fail-on=
# Specify a score threshold under which the program will exit with error.
fail-under=10
# Interpret the stdin as a python script, whose filename needs to be passed as
# the module_or_package argument.
#from-stdin=
# Files or directories to be skipped. They should be base names, not paths.
ignore=CVS
# Add files or directories matching the regular expressions patterns to the
# ignore-list. The regex matches against paths and can be in Posix or Windows
# format. Because '\\' represents the directory delimiter on Windows systems,
# it can't be used as an escape character.
ignore-paths=
# Files or directories matching the regular expression patterns are skipped.
# The regex matches against base names, not paths. The default value ignores
# Emacs file locks
ignore-patterns=^\.#
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use, and will cap the count on Windows to
# avoid hangs.
jobs=1
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Minimum Python version to use for version dependent checks. Will default to
# the version used to run pylint.
py-version=3.12
# Discover python modules and packages in the file system subtree.
recursive=no
# Add paths to the list of the source roots. Supports globbing patterns. The
# source root is an absolute path or a path relative to the current working
# directory used to determine a package namespace for modules located under the
# source root.
source-roots=
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
# In verbose mode, extra non-checker-related info will be displayed.
#verbose=
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style. If left empty, argument names will be checked with the set
# naming style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style. If left empty, attribute names will be checked with the set naming
# style.
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Bad variable names regexes, separated by a comma. If names match any regex,
# they will always be refused
bad-names-rgxs=
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style. If left empty, class attribute names will be checked
# with the set naming style.
#class-attribute-rgx=
# Naming style matching correct class constant names.
class-const-naming-style=UPPER_CASE
# Regular expression matching correct class constant names. Overrides class-
# const-naming-style. If left empty, class constant names will be checked with
# the set naming style.
#class-const-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style. If left empty, class names will be checked with the set naming style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style. If left empty, constant names will be checked with the set naming
# style.
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style. If left empty, function names will be checked with the set
# naming style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_
# Good variable names regexes, separated by a comma. If names match any regex,
# they will always be accepted
good-names-rgxs=
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style. If left empty, inline iteration names will be checked
# with the set naming style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style. If left empty, method names will be checked with the set naming style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style. If left empty, module names will be checked with the set naming style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Regular expression matching correct type alias names. If left empty, type
# alias names will be checked with the set naming style.
#typealias-rgx=
# Regular expression matching correct type variable names. If left empty, type
# variable names will be checked with the set naming style.
#typevar-rgx=
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style. If left empty, variable names will be checked with the set
# naming style.
#variable-rgx=
[CLASSES]
# Warn about protected attribute access inside special methods
check-protected-access-in-special-methods=no
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
asyncSetUp,
__post_init__
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# List of regular expressions of class ancestor names to ignore when counting
# public methods (see R0903)
exclude-too-few-public-methods=
# List of qualified class names to ignore when counting class parents (see
# R0901)
ignored-parents=
# Maximum number of arguments for function / method.
max-args=6
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=30
# Maximum number of locals for function / method body.
max-locals=30
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=75
# Minimum number of public methods for a class (see R0903).
min-public-methods=0
[EXCEPTIONS]
# Exceptions that will emit a warning when caught.
overgeneral-exceptions=builtins.BaseException,builtins.Exception
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=2
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=200
# Maximum number of lines in a module.
max-module-lines=1000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[IMPORTS]
# List of modules that can be imported at any level, not just the top level
# one.
allow-any-import-level=
# Allow explicit reexports by alias from a package __init__.
allow-reexport-from-package=no
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=
# Output a graph (.gv or any supported image format) of external dependencies
# to the given file (report RP0402 must not be disabled).
ext-import-graph=
# Output a graph (.gv or any supported image format) of all (i.e. internal and
# external) dependencies to the given file (report RP0402 must not be
# disabled).
import-graph=
# Output a graph (.gv or any supported image format) of internal dependencies
# to the given file (report RP0402 must not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
# Couples of modules and preferred modules, separated by a comma.
preferred-modules=
[LOGGING]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
# UNDEFINED.
confidence=HIGH,
CONTROL_FLOW,
INFERENCE,
INFERENCE_FAILURE,
UNDEFINED
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then re-enable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
fixme
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[METHOD_ARGS]
# List of qualified names (i.e., library.method) which require a timeout
# parameter e.g. 'requests.api.get,requests.api.post'
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
notes-rgx=
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit,argparse.parse_error
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
# 'convention', and 'info' which contain the number of messages in each
# category, as well as 'statement' which is the total number of statements
# analyzed. This score is used by the global evaluation report (RP0004).
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
#output-format=
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[SIMILARITIES]
# Comments are removed from the similarity computation
ignore-comments=yes
# Docstrings are removed from the similarity computation
ignore-docstrings=yes
# Imports are removed from the similarity computation
ignore-imports=yes
# Signatures are removed from the similarity computation
ignore-signatures=yes
# Minimum lines number of a similarity.
min-similarity-lines=16
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. No available dictionaries : You need to install
# both the python package and the system dependency for enchant to work..
spelling-dict=
# List of comma separated words that should be considered directives if they
# appear at the beginning of a comment and should not be checked.
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of symbolic message names to ignore for Mixin members.
ignored-checks-for-mixins=no-member,
not-async-context-manager,
not-context-manager,
attribute-defined-outside-init
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# Regex pattern to define which classes are considered mixins.
mixin-class-rgx=.*[Mm]ixin
# List of decorators that change the signature of a decorated function.
signature-mutators=
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of names allowed to shadow builtins
allowed-redefined-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io

View File

@ -310,7 +310,7 @@ target_sources(lego1 PRIVATE
LEGO1/lego/sources/misc/legostorage.cpp LEGO1/lego/sources/misc/legostorage.cpp
LEGO1/lego/sources/misc/legotexture.cpp LEGO1/lego/sources/misc/legotexture.cpp
LEGO1/lego/sources/misc/legotree.cpp LEGO1/lego/sources/misc/legotree.cpp
LEGO1/lego/sources/misc/legounknown.cpp LEGO1/lego/sources/misc/legospline.cpp
) )
target_include_directories(lego1 PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/LEGO1/lego/sources") target_include_directories(lego1 PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/LEGO1/lego/sources")

View File

@ -29,18 +29,18 @@ class Act2Actor : public LegoAnimActor {
void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30
// FUNCTION: LEGO1 0x1001a180 // FUNCTION: LEGO1 0x1001a180
MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override MxS32 CheckIntersections(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override
{ {
if (m_animatingHit) { if (m_animatingHit) {
return 0; return 0;
} }
return LegoAnimActor::VTable0x68(p_v1, p_v2, p_v3); return LegoAnimActor::CheckIntersections(p_v1, p_v2, p_v3);
} // vtable+0x68 } // vtable+0x68
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94 MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
MxS32 NextTargetLocation() override; // vtable+0xa0 MxS32 NextTargetLocation() override; // vtable+0xa0
void InitializeNextShot(); void InitializeNextShot();

View File

@ -57,7 +57,7 @@ class Act3Actor : public LegoAnimActor {
public: public:
Act3Actor(); Act3Actor();
MxU32 VTable0x90(float p_time, Matrix4& p_transform) override; // vtable+0x90 MxU32 StepState(float p_time, Matrix4& p_transform) override; // vtable+0x90
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
// FUNCTION: LEGO1 0x100431b0 // FUNCTION: LEGO1 0x100431b0
@ -105,7 +105,7 @@ class Act3Cop : public Act3Actor {
void ParseAction(char* p_extra) override; // vtable+0x20 void ParseAction(char* p_extra) override; // vtable+0x20
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94 MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
MxFloat GetUnknown0x20() { return m_unk0x20; } MxFloat GetUnknown0x20() { return m_unk0x20; }
@ -142,8 +142,8 @@ class Act3Brickster : public Act3Actor {
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
float& p_unk0xe4 float& p_unk0xe4
) override; // vtable+0x98 ) override; // vtable+0x98
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
MxFloat GetUnknown0x20() { return m_unk0x20; } MxFloat GetUnknown0x20() { return m_unk0x20; }
MxFloat GetUnknown0x24() { return m_unk0x24; } MxFloat GetUnknown0x24() { return m_unk0x24; }

View File

@ -14,7 +14,7 @@ class Act3Ammo : public LegoPathActor {
c_pizza = 0x01, c_pizza = 0x01,
c_donut = 0x02, c_donut = 0x02,
c_valid = 0x04, c_valid = 0x04,
c_bit4 = 0x08, c_withoutBoundary = 0x08,
c_sharkFood = 0x10 c_sharkFood = 0x10
}; };
@ -28,10 +28,10 @@ class Act3Ammo : public LegoPathActor {
MxU32 IsValid() { return m_ammoFlag & c_valid; } MxU32 IsValid() { return m_ammoFlag & c_valid; }
// FUNCTION: BETA10 0x100177b0 // FUNCTION: BETA10 0x100177b0
Mx3DPointFloat* GetUnknown0x160() { return m_eq; } Mx3DPointFloat* GetCoefficients() { return m_coefficients; }
// FUNCTION: BETA10 0x100177e0 // FUNCTION: BETA10 0x100177e0
MxFloat* GetUnknown0x19c() { return &m_unk0x19c; } MxFloat* GetApexParameter() { return &m_apexParameter; }
// FUNCTION: BETA10 0x1001fbd0 // FUNCTION: BETA10 0x1001fbd0
void SetValid(MxBool p_valid) void SetValid(MxBool p_valid)
@ -51,18 +51,18 @@ class Act3Ammo : public LegoPathActor {
MxU32 IsDonut() { return m_ammoFlag & c_donut; } MxU32 IsDonut() { return m_ammoFlag & c_donut; }
// FUNCTION: BETA10 0x1001fcb0 // FUNCTION: BETA10 0x1001fcb0
void SetBit4(MxBool p_bit4) void SetShootWithoutBoundary(MxBool p_withoutBoundary)
{ {
if (p_bit4) { if (p_withoutBoundary) {
m_ammoFlag |= c_bit4; m_ammoFlag |= c_withoutBoundary;
} }
else { else {
m_ammoFlag &= ~c_bit4; m_ammoFlag &= ~c_withoutBoundary;
} }
} }
// FUNCTION: BETA10 0x10021d90 // FUNCTION: BETA10 0x10021d90
MxU32 IsBit4() { return m_ammoFlag & c_bit4; } MxU32 IsShootWithoutBoundary() { return m_ammoFlag & c_withoutBoundary; }
void SetSharkFood(MxBool p_sharkFood) void SetSharkFood(MxBool p_sharkFood)
{ {
@ -76,29 +76,29 @@ class Act3Ammo : public LegoPathActor {
MxU32 IsSharkFood() { return m_ammoFlag & c_sharkFood; } MxU32 IsSharkFood() { return m_ammoFlag & c_sharkFood; }
MxFloat GetUnknown0x158() { return m_unk0x158; } MxFloat GetRotateTimeout() { return m_rotateTimeout; }
void SetUnknown0x158(MxFloat p_unk0x158) { m_unk0x158 = p_unk0x158; } void SetRotateTimeout(MxFloat p_rotateTimeout) { m_rotateTimeout = p_rotateTimeout; }
MxResult Remove(); MxResult Remove();
MxResult Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index); MxResult Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index);
MxResult FUN_10053b40(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp); MxResult CalculateArc(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp);
MxResult FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_unk0x19c); MxResult Shoot(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_apexParameter);
MxResult FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c); MxResult Shoot(LegoPathController* p_p, MxFloat p_apexParameter);
// SYNTHETIC: LEGO1 0x10053880 // SYNTHETIC: LEGO1 0x10053880
// Act3Ammo::`scalar deleting destructor' // Act3Ammo::`scalar deleting destructor'
private: private:
MxResult FUN_10053db0(float p_param1, Matrix4& p_param2); MxResult CalculateTransformOnCurve(float p_curveParameter, Matrix4& p_transform);
static Mx3DPointFloat g_unk0x10104f08; static Mx3DPointFloat g_hitTranslation;
MxU16 m_ammoFlag; // 0x154 MxU16 m_ammoFlag; // 0x154
MxFloat m_unk0x158; // 0x158 MxFloat m_rotateTimeout; // 0x158
Act3* m_world; // 0x15c Act3* m_world; // 0x15c
Mx3DPointFloat m_eq[3]; // 0x160 Mx3DPointFloat m_coefficients[3]; // 0x160
MxFloat m_unk0x19c; // 0x19c MxFloat m_apexParameter; // 0x19c
}; };
#endif // ACT3AMMO_H #endif // ACT3AMMO_H

View File

@ -10,7 +10,7 @@ class LegoROI;
// SIZE 0x1f8 // SIZE 0x1f8
class Doors : public LegoPathActor { class Doors : public LegoPathActor {
public: public:
Doors() : m_unk0x154(0), m_ltDoor(NULL), m_rtDoor(NULL), m_unk0x1f4(0) {} Doors() : m_state(0), m_ltDoor(NULL), m_rtDoor(NULL), m_angle(0) {}
// FUNCTION: LEGO1 0x1000e430 // FUNCTION: LEGO1 0x1000e430
// FUNCTION: BETA10 0x100a7f20 // FUNCTION: BETA10 0x100a7f20
@ -29,19 +29,25 @@ class Doors : public LegoPathActor {
void ParseAction(char* p_extra) override; // vtable+0x20 void ParseAction(char* p_extra) override; // vtable+0x20
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
virtual MxFloat VTable0xcc(float p_time); // vtable+0xcc virtual MxFloat CalculateAngle(float p_time); // vtable+0xcc
// SYNTHETIC: LEGO1 0x1000e580 // SYNTHETIC: LEGO1 0x1000e580
// Doors::`scalar deleting destructor' // Doors::`scalar deleting destructor'
private: private:
undefined4 m_unk0x154; // 0x154 enum {
MxFloat m_unk0x158; // 0x158 e_none = 0,
LegoROI* m_ltDoor; // 0x15c e_closed = 1,
LegoROI* m_rtDoor; // 0x160 e_cycling = 2,
MxMatrix m_ltDoorLocal; // 0x164 };
MxMatrix m_rtDoorLocal; // 0x1ac
MxFloat m_unk0x1f4; // 0x1f4 undefined4 m_state; // 0x154
MxFloat m_hitTime; // 0x158
LegoROI* m_ltDoor; // 0x15c
LegoROI* m_rtDoor; // 0x160
MxMatrix m_ltDoorOriginalLocal; // 0x164
MxMatrix m_rtDoorOriginalLocal; // 0x1ac
MxFloat m_angle; // 0x1f4
}; };
#endif // DOORS_H #endif // DOORS_H

View File

@ -69,7 +69,7 @@ class Helicopter : public IslePathActor {
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74
MxLong HandleClick() override; // vtable+0xcc MxLong HandleClick() override; // vtable+0xcc
MxLong HandleControl(LegoControlManagerNotificationParam& p_param) override; // vtable+0xd4 MxLong HandleControl(LegoControlManagerNotificationParam& p_param) override; // vtable+0xd4
MxLong HandleEndAnim(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8 MxLong HandleEndAnim(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8

View File

@ -102,10 +102,10 @@ class IslePathActor : public LegoPathActor {
// FUNCTION: LEGO1 0x10002e00 // FUNCTION: LEGO1 0x10002e00
virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0xdc virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0xdc
virtual void Enter(); // vtable+0xe0 virtual void Enter(); // vtable+0xe0
virtual void Exit(); // vtable+0xe4 virtual void Exit(); // vtable+0xe4
virtual void SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 p_flags); // vtable+0xe8 virtual void SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 p_flags); // vtable+0xe8
virtual void VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset); // vtable+0xec virtual void UpdateWorld(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset); // vtable+0xec
// FUNCTION: LEGO1 0x10002e10 // FUNCTION: LEGO1 0x10002e10
~IslePathActor() override { IslePathActor::Destroy(TRUE); } ~IslePathActor() override { IslePathActor::Destroy(TRUE); }
@ -129,7 +129,7 @@ class IslePathActor : public LegoPathActor {
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c
void FUN_1001b660(); void TurnAround();
void SetWorld(LegoWorld* p_world) { m_world = p_world; } void SetWorld(LegoWorld* p_world) { m_world = p_world; }

View File

@ -10,7 +10,7 @@
// SIZE 0x68 // SIZE 0x68
class LegoActionControlPresenter : public MxMediaPresenter { class LegoActionControlPresenter : public MxMediaPresenter {
public: public:
LegoActionControlPresenter() : m_unk0x50(Extra::ActionType::e_none) {} LegoActionControlPresenter() : m_actionType(Extra::ActionType::e_none) {}
~LegoActionControlPresenter() override { Destroy(TRUE); } // vtable+0x00 ~LegoActionControlPresenter() override { Destroy(TRUE); } // vtable+0x00
// FUNCTION: BETA10 0x100a7840 // FUNCTION: BETA10 0x100a7840
@ -40,9 +40,9 @@ class LegoActionControlPresenter : public MxMediaPresenter {
virtual void Destroy(MxBool p_fromDestructor); // vtable+0x5c virtual void Destroy(MxBool p_fromDestructor); // vtable+0x5c
private: private:
Extra::ActionType m_unk0x50; // 0x50 Extra::ActionType m_actionType; // 0x50
MxString m_unk0x54; // 0x54 MxString m_sourceName; // 0x54
undefined4 m_unk0x64; // 0x64 undefined4 m_streamId; // 0x64
}; };
// SYNTHETIC: LEGO1 0x1000d1d0 // SYNTHETIC: LEGO1 0x1000d1d0

View File

@ -42,10 +42,10 @@ class LegoAnimActor : public virtual LegoPathActor {
~LegoAnimActor() override; ~LegoAnimActor() override;
void ParseAction(char* p_extra) override; // vtable+0x20 void ParseAction(char* p_extra) override; // vtable+0x20
void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74
virtual MxResult GetTimeInCycle(float& p_timeInCycle); virtual MxResult GetTimeInCycle(float& p_timeInCycle);
virtual MxResult AnimateWithTransform(float p_time, Matrix4& p_transform); virtual MxResult AnimateWithTransform(float p_time, Matrix4& p_transform);

View File

@ -61,7 +61,7 @@ class LegoAnimMMPresenter : public MxCompositePresenter {
void ParseExtra() override; // vtable+0x30 void ParseExtra() override; // vtable+0x30
MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c
void EndAction() override; // vtable+0x40 void EndAction() override; // vtable+0x40
void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 void AdvanceSerialAction(MxPresenter* p_presenter) override; // vtable+0x60
// SYNTHETIC: LEGO1 0x1004aa40 // SYNTHETIC: LEGO1 0x1004aa40
// LegoAnimMMPresenter::`scalar deleting destructor' // LegoAnimMMPresenter::`scalar deleting destructor'

View File

@ -62,21 +62,27 @@ class LegoAnimPresenter : public MxVideoPresenter {
return !strcmp(p_name, LegoAnimPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); return !strcmp(p_name, LegoAnimPresenter::ClassName()) || MxVideoPresenter::IsA(p_name);
} }
void ReadyTickle() override; // vtable+0x18 void ReadyTickle() override; // vtable+0x18
void StartingTickle() override; // vtable+0x1c void StartingTickle() override; // vtable+0x1c
void StreamingTickle() override; // vtable+0x20 void StreamingTickle() override; // vtable+0x20
void DoneTickle() override; // vtable+0x2c void DoneTickle() override; // vtable+0x2c
void ParseExtra() override; // vtable+0x30 void ParseExtra() override; // vtable+0x30
MxResult AddToManager() override; // vtable+0x34 MxResult AddToManager() override; // vtable+0x34
void Destroy() override; // vtable+0x38 void Destroy() override; // vtable+0x38
MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c
void EndAction() override; // vtable+0x40 void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c void PutFrame() override; // vtable+0x6c
virtual MxResult CreateAnim(MxStreamChunk* p_chunk); // vtable+0x88 virtual MxResult CreateAnim(MxStreamChunk* p_chunk); // vtable+0x88
virtual void VTable0x8c(); // vtable+0x8c virtual void AddToWorld(); // vtable+0x8c
virtual void VTable0x90(); // vtable+0x90 virtual void RemoveFromWorld(); // vtable+0x90
virtual MxU32 VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3); // vtable+0x94 virtual MxU32 Intersect(
virtual MxResult VTable0x98(LegoPathBoundary* p_boundary); // vtable+0x98 Vector3& p_rayOrigin,
Vector3& p_rayDirection,
float p_rayLength,
float p_radius,
Vector3& p_intersectionPoint
); // vtable+0x94
virtual MxResult AddActors(LegoPathBoundary* p_boundary); // vtable+0x98
// FUNCTION: LEGO1 0x1000c990 // FUNCTION: LEGO1 0x1000c990
virtual LegoROI** GetROIMap(MxU32& p_roiMapSize) virtual LegoROI** GetROIMap(MxU32& p_roiMapSize)
@ -85,47 +91,47 @@ class LegoAnimPresenter : public MxVideoPresenter {
return m_roiMap; return m_roiMap;
} // vtable+0x9c } // vtable+0x9c
virtual void VTable0xa0(Matrix4& p_matrix); // vtable+0xa0 virtual void SetTransform(Matrix4& p_matrix); // vtable+0xa0
MxResult FUN_1006afc0(MxMatrix*& p_matrix, float p_und); MxResult GetTransforms(MxMatrix*& p_matrix, float p_time);
MxResult FUN_1006b140(LegoROI* p_roi); MxResult CopyTransform(LegoROI* p_roi);
void FUN_1006c7a0(); void ApplyFinishedTransform();
const char* GetActionObjectName(); const char* GetActionObjectName();
void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; } void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; }
// FUNCTION: BETA10 0x1005aad0 // FUNCTION: BETA10 0x1005aad0
void SetUnknown0x0cTo1() { m_unk0x9c = 1; } void SetRoiTransformApplied() { m_roiTransformApplied = 1; }
// FUNCTION: BETA10 0x1005ab00 // FUNCTION: BETA10 0x1005ab00
void SetUnknown0xa0(Matrix4* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } void SetRoiTransform(Matrix4* p_roiTransform) { m_roiTransform = p_roiTransform; }
LegoAnim* GetAnimation() { return m_anim; } LegoAnim* GetAnimation() { return m_anim; }
protected: protected:
void Init(); void Init();
void Destroy(MxBool p_fromDestructor); void Destroy(MxBool p_fromDestructor);
LegoChar* FUN_10069150(const LegoChar* p_und1); LegoChar* GetActorName(const LegoChar* p_name);
void FUN_100692b0(); void CreateManagedActors();
void FUN_100695c0(); void CreateSceneROIs();
LegoChar* GetVariableOrIdentity(const LegoChar* p_varName, const LegoChar* p_prefix); LegoChar* GetVariableOrIdentity(const LegoChar* p_varName, const LegoChar* p_prefix);
LegoBool FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2); LegoBool AppendROIToScene(const CompoundObject& p_rois, const LegoChar* p_varName);
LegoROI* FindROI(const LegoChar* p_name); LegoROI* FindROI(const LegoChar* p_name);
void FUN_10069b10(); void BuildROIMap();
void UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi); void UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi);
void UpdateStructMapAndROIIndexForNode( void UpdateStructMapAndROIIndexForNode(
LegoAnimStructMap& p_map, LegoAnimStructMap& p_map,
LegoAnimNodeData* p_data, LegoAnimNodeData* p_data,
const LegoChar* p_und, const LegoChar* p_key,
LegoROI* p_roi LegoROI* p_roi
); );
void FUN_1006aa60(); void ReleaseManagedActors();
void FUN_1006ab70(); void AppendManagedActors();
LegoBool FUN_1006aba0(); LegoBool VerifyAnimationTree();
MxBool FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi); MxBool VerifyAnimationNode(LegoTreeNode* p_node, LegoROI* p_roi);
void SubstituteVariables(); void SubstituteVariables();
void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void ApplyTransform(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void ApplyTransformWithVisibilityAndCam(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void SetDisabled(MxBool p_disabled); void SetDisabled(MxBool p_disabled);
LegoAnim* m_anim; // 0x64 LegoAnim* m_anim; // 0x64
@ -133,27 +139,27 @@ class LegoAnimPresenter : public MxVideoPresenter {
MxU32 m_roiMapSize; // 0x6c MxU32 m_roiMapSize; // 0x6c
LegoROIList* m_sceneROIs; // 0x70 LegoROIList* m_sceneROIs; // 0x70
LegoROIList* m_managedActors; // 0x74 LegoROIList* m_managedActors; // 0x74
Matrix4* m_unk0x78; // 0x78 Matrix4* m_transform; // 0x78
MxU32 m_flags; // 0x7c MxU32 m_flags; // 0x7c
LegoWorld* m_currentWorld; // 0x80 LegoWorld* m_currentWorld; // 0x80
MxAtomId m_worldAtom; // 0x84 MxAtomId m_worldAtom; // 0x84
MxS32 m_worldId; // 0x88 MxS32 m_worldId; // 0x88
LegoROI** m_unk0x8c; // 0x8c LegoROI** m_ptAtCamROI; // 0x8c
char** m_unk0x90; // 0x90 char** m_ptAtCamNames; // 0x90
MxU8 m_unk0x94; // 0x94 MxU8 m_ptAtCamCount; // 0x94
MxBool m_unk0x95; // 0x95 MxBool m_animationFinished; // 0x95
MxBool m_unk0x96; // 0x96 MxBool m_localActors; // 0x96
undefined m_unk0x97; // 0x97 undefined m_unk0x97; // 0x97
LegoAnimSubstMap* m_substMap; // 0x98 LegoAnimSubstMap* m_substMap; // 0x98
MxS16 m_unk0x9c; // 0x9c MxS16 m_roiTransformApplied; // 0x9c
Matrix4* m_unk0xa0; // 0xa0 Matrix4* m_roiTransform; // 0xa0
// SYNTHETIC: LEGO1 0x10068650 // SYNTHETIC: LEGO1 0x10068650
// LegoAnimPresenter::`scalar deleting destructor' // LegoAnimPresenter::`scalar deleting destructor'
public: public:
float m_unk0xa4; // 0xa4 float m_boundingRadius; // 0xa4
Mx3DPointFloat m_unk0xa8; // 0xa8 Mx3DPointFloat m_centerPoint; // 0xa8
}; };
// VTABLE: LEGO1 0x100d4900 // VTABLE: LEGO1 0x100d4900
@ -231,16 +237,16 @@ class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter {
void PutFrame() override; // vtable+0x6c void PutFrame() override; // vtable+0x6c
MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88 MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88
void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); void CreateROIAndBuildMap(LegoAnimActor* p_actor, MxFloat p_worldSpeed);
void DecrementUnknown0xd4() void DecrementWorldRefCounter()
{ {
if (m_unk0xd4) { if (m_worldRefCounter) {
--m_unk0xd4; --m_worldRefCounter;
} }
} }
undefined2 GetUnknown0xd4() { return m_unk0xd4; } MxS16 GetWorldRefCounter() { return m_worldRefCounter; }
// SYNTHETIC: LEGO1 0x1006cfe0 // SYNTHETIC: LEGO1 0x1006cfe0
// LegoLocomotionAnimPresenter::`scalar deleting destructor' // LegoLocomotionAnimPresenter::`scalar deleting destructor'
@ -254,7 +260,7 @@ class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter {
LegoROIMapList* m_roiMapList; // 0xc8 LegoROIMapList* m_roiMapList; // 0xc8
MxS32 m_unk0xcc; // 0xcc MxS32 m_unk0xcc; // 0xcc
MxS32 m_unk0xd0; // 0xd0 MxS32 m_unk0xd0; // 0xd0
undefined2 m_unk0xd4; // 0xd4 MxS16 m_worldRefCounter; // 0xd4
}; };
class LegoPathBoundary; class LegoPathBoundary;
@ -279,10 +285,10 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
~LegoHideAnimPresenter() override; ~LegoHideAnimPresenter() override;
// FUNCTION: LEGO1 0x1006d860 // FUNCTION: LEGO1 0x1006d860
void VTable0x8c() override {} // vtable+0x8c void AddToWorld() override {} // vtable+0x8c
// FUNCTION: LEGO1 0x1006d870 // FUNCTION: LEGO1 0x1006d870
void VTable0x90() override {} // vtable+0x90 void RemoveFromWorld() override {} // vtable+0x90
// FUNCTION: BETA10 0x1005d4a0 // FUNCTION: BETA10 0x1005d4a0
static const char* HandlerClassName() static const char* HandlerClassName()
@ -311,7 +317,7 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
void EndAction() override; // vtable+0x40 void EndAction() override; // vtable+0x40
void PutFrame() override; // vtable+0x6c void PutFrame() override; // vtable+0x6c
void FUN_1006db40(LegoTime p_time); void ApplyVisibility(LegoTime p_time);
// SYNTHETIC: LEGO1 0x1006d9d0 // SYNTHETIC: LEGO1 0x1006d9d0
// LegoHideAnimPresenter::`scalar deleting destructor' // LegoHideAnimPresenter::`scalar deleting destructor'
@ -319,10 +325,10 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
private: private:
void Init(); void Init();
void Destroy(MxBool p_fromDestructor); void Destroy(MxBool p_fromDestructor);
void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time); void ApplyVisibility(LegoTreeNode* p_node, LegoTime p_time);
void FUN_1006dc10(); void AssignIndiciesWithMap();
void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); void BuildMap(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node);
void FUN_1006e470( void CheckedAdd(
LegoHideAnimStructMap& p_map, LegoHideAnimStructMap& p_map,
LegoAnimNodeData* p_data, LegoAnimNodeData* p_data,
const char* p_name, const char* p_name,

View File

@ -43,8 +43,13 @@ class LegoEventNotificationParam : public MxNotificationParam {
{ {
} }
// FUNCTION: BETA10 0x10026070
LegoROI* GetROI() { return m_roi; } LegoROI* GetROI() { return m_roi; }
// FUNCTION: BETA10 0x1006aab0
MxU8 GetModifier() { return m_modifier; } MxU8 GetModifier() { return m_modifier; }
// FUNCTION: BETA10 0x100179a0
SDL_Keycode GetKey() const { return m_key; } SDL_Keycode GetKey() const { return m_key; }
// FUNCTION: LEGO1 0x10012190 // FUNCTION: LEGO1 0x10012190

View File

@ -36,45 +36,52 @@ class LegoExtraActor : public virtual LegoAnimActor {
return !strcmp(p_name, LegoExtraActor::ClassName()) || LegoAnimActor::IsA(p_name); return !strcmp(p_name, LegoExtraActor::ClassName()) || LegoAnimActor::IsA(p_name);
} }
void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30
MxS32 VTable0x68(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3) override; // vtable+0x68 MxS32 CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint)
inline MxU32 VTable0x6c( override; // vtable+0x68
inline MxU32 CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) override; // vtable+0x6c ) override; // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74
MxU32 VTable0x90(float p_time, Matrix4& p_matrix) override; // vtable+0x90 MxU32 StepState(float p_time, Matrix4& p_matrix) override; // vtable+0x90
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
void VTable0xa4(MxBool& p_und1, MxS32& p_und2) override; // vtable+0xa4 void GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex) override; // vtable+0xa4
void VTable0xc4() override; // vtable+0xc4 void VTable0xc4() override; // vtable+0xc4
virtual MxResult FUN_1002aae0(); virtual MxResult SwitchDirection();
void Restart(); void Restart();
inline void FUN_1002ad8a(); inline void InitializeReassemblyAnim();
void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } void SetPathWalkingMode(MxU8 p_pathWalkingMode) { m_pathWalkingMode = p_pathWalkingMode; }
// SYNTHETIC: LEGO1 0x1002b760 // SYNTHETIC: LEGO1 0x1002b760
// LegoExtraActor::`scalar deleting destructor' // LegoExtraActor::`scalar deleting destructor'
private: private:
MxFloat m_scheduledTime; // 0x08 enum {
undefined m_unk0x0c; // 0x0c e_none = 0,
MxU8 m_axis; // 0x0d e_disassemble = 1,
undefined m_unk0x0e; // 0x0e e_assemble = 2,
MxFloat m_prevWorldSpeed; // 0x10 };
MxU8 m_whichAnim; // 0x14
MxU8 m_unk0x15; // 0x15 MxFloat m_scheduledTime; // 0x08
MxMatrix m_unk0x18; // 0x18 MxU8 m_pathWalkingMode; // 0x0c
LegoAnimActorStruct* m_assAnim; // 0x60 MxU8 m_axis; // 0x0d
LegoAnimActorStruct* m_disAnim; // 0x64 MxBool m_animationAtCurrentBoundary; // 0x0e
MxFloat m_prevWorldSpeed; // 0x10
MxU8 m_reassemblyAnimation; // 0x14
MxU8 m_hitBlockCounter; // 0x15
MxMatrix m_localBeforeHit; // 0x18
LegoAnimActorStruct* m_assAnim; // 0x60
LegoAnimActorStruct* m_disAnim; // 0x64
}; };
// GLOBAL: LEGO1 0x100d6be8 // GLOBAL: LEGO1 0x100d6be8

View File

@ -44,7 +44,7 @@ class LegoNavController : public MxCore {
const Vector3& p_curDir, const Vector3& p_curDir,
Vector3& p_newPos, Vector3& p_newPos,
Vector3& p_newDir, Vector3& p_newDir,
const Vector3* p_und const Vector3* p_up
); );
static void GetDefaults( static void GetDefaults(
@ -126,36 +126,36 @@ class LegoNavController : public MxCore {
float CalculateNewTargetVel(int p_pos, int p_center, float p_max); float CalculateNewTargetVel(int p_pos, int p_center, float p_max);
float CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min); float CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min);
MxResult ProcessJoystickInput(MxBool& p_und); MxResult ProcessJoystickInput(MxBool& p_rotatedY);
MxResult ProcessKeyboardInput(); MxResult ProcessKeyboardInput();
int m_hMax; // 0x08 int m_hMax; // 0x08
int m_vMax; // 0x0c int m_vMax; // 0x0c
int m_deadZone; // 0x10 int m_deadZone; // 0x10
float m_zeroThreshold; // 0x14 float m_zeroThreshold; // 0x14
float m_linearVel; // 0x18 float m_linearVel; // 0x18
float m_rotationalVel; // 0x1c float m_rotationalVel; // 0x1c
float m_targetLinearVel; // 0x20 float m_targetLinearVel; // 0x20
float m_targetRotationalVel; // 0x24 float m_targetRotationalVel; // 0x24
float m_maxLinearVel; // 0x28 float m_maxLinearVel; // 0x28
float m_maxRotationalVel; // 0x2c float m_maxRotationalVel; // 0x2c
float m_linearAccel; // 0x30 float m_linearAccel; // 0x30
float m_rotationalAccel; // 0x34 float m_rotationalAccel; // 0x34
float m_maxLinearAccel; // 0x38 float m_maxLinearAccel; // 0x38
float m_maxRotationalAccel; // 0x3c float m_maxRotationalAccel; // 0x3c
float m_minLinearAccel; // 0x40 float m_minLinearAccel; // 0x40
float m_minRotationalAccel; // 0x44 float m_minRotationalAccel; // 0x44
float m_maxLinearDeccel; // 0x48 float m_maxLinearDeccel; // 0x48
float m_maxRotationalDeccel; // 0x4c float m_maxRotationalDeccel; // 0x4c
float m_rotSensitivity; // 0x50 float m_rotSensitivity; // 0x50
MxBool m_useRotationalVel; // 0x54 MxBool m_useRotationalVel; // 0x54
MxTime m_lastTime; // 0x58 MxTime m_lastTime; // 0x58
MxBool m_trackDefault; // 0x5c MxBool m_trackDefault; // 0x5c
MxBool m_unk0x5d; // 0x5d MxBool m_keyPressed; // 0x5d
float m_unk0x60; // 0x60 float m_additionalHeightOffset; // 0x60
float m_unk0x64; // 0x64 float m_additionalScale; // 0x64
float m_unk0x68; // 0x68 float m_additionalRotationY; // 0x68
MxBool m_isAccelerating; // 0x6c MxBool m_isAccelerating; // 0x6c
// one copy of defaults (these can be set by App.) // one copy of defaults (these can be set by App.)
static int g_defdeadZone; static int g_defdeadZone;

View File

@ -2,7 +2,7 @@
#define LEGOPATHACTOR_H #define LEGOPATHACTOR_H
#include "legoactor.h" #include "legoactor.h"
#include "misc/legounknown.h" #include "misc/legospline.h"
#include "mxtypes.h" #include "mxtypes.h"
struct LegoEdge; struct LegoEdge;
@ -24,9 +24,9 @@ class LegoPathActor : public LegoActor {
enum ActorState { enum ActorState {
// States // States
c_initial = 0, c_initial = 0,
c_one = 1, c_ready = 1,
c_two = 2, c_hit = 2,
c_three = 3, c_hitAnimation = 3,
c_disabled = 4, c_disabled = 4,
c_maxState = 255, c_maxState = 255,
@ -37,18 +37,22 @@ class LegoPathActor : public LegoActor {
LegoPathActor(); LegoPathActor();
~LegoPathActor() override; ~LegoPathActor() override;
void ParseAction(char* p_extra) override; // vtable+0x20 void ParseAction(char* p_extra) override; // vtable+0x20
virtual MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3); // vtable+0x68 virtual MxS32 CheckIntersections(
virtual MxU32 VTable0x6c( Vector3& p_rayOrigin,
Vector3& p_rayEnd,
Vector3& p_intersectionPoint
); // vtable+0x68
virtual MxU32 CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
); // vtable+0x6c ); // vtable+0x6c
virtual void Animate(float p_time); // vtable+0x70 virtual void Animate(float p_time); // vtable+0x70
virtual void VTable0x74(Matrix4& p_transform); // vtable+0x74 virtual void ApplyTransform(Matrix4& p_transform); // vtable+0x74
// FUNCTION: LEGO1 0x10002d20 // FUNCTION: LEGO1 0x10002d20
// FUNCTION: BETA10 0x1000f500 // FUNCTION: BETA10 0x1000f500
@ -58,33 +62,33 @@ class LegoPathActor : public LegoActor {
// FUNCTION: BETA10 0x1000f530 // FUNCTION: BETA10 0x1000f530
virtual MxBool GetUserNavFlag() { return m_userNavFlag; } // vtable+0x7c virtual MxBool GetUserNavFlag() { return m_userNavFlag; } // vtable+0x7c
virtual MxResult VTable0x80( virtual MxResult SetSpline(
const Vector3& p_point1, const Vector3& p_start,
Vector3& p_point2, Vector3& p_tangentAtStart,
Vector3& p_point3, Vector3& p_end,
Vector3& p_point4 Vector3& p_tangentAtEnd
); // vtable+0x80 ); // vtable+0x80
virtual MxResult VTable0x84( virtual MxResult SetTransformAndDestinationFromPoints(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
float p_time, float p_time,
Vector3& p_p1, Vector3& p_start,
Vector3& p_p4, Vector3& p_direction,
LegoOrientedEdge* p_destEdge, LegoOrientedEdge* p_destEdge,
float p_destScale float p_destScale
); // vtable+0x84 ); // vtable+0x84
virtual MxResult VTable0x88( virtual MxResult SetTransformAndDestinationFromEdge(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
float p_time, float p_time,
LegoEdge& p_srcEdge, LegoEdge& p_srcEdge,
float p_srcScale, float p_srcScale,
LegoOrientedEdge& p_destEdge, LegoOrientedEdge& p_destEdge,
float p_destScale float p_destScale
); // vtable+0x88 ); // vtable+0x88
virtual MxS32 VTable0x8c(float p_time, Matrix4& p_transform); // vtable+0x8c virtual MxS32 CalculateTransform(float p_time, Matrix4& p_transform); // vtable+0x8c
// FUNCTION: LEGO1 0x10002d40 // FUNCTION: LEGO1 0x10002d40
// FUNCTION: BETA10 0x1000f560 // FUNCTION: BETA10 0x1000f560
virtual MxU32 VTable0x90(float, Matrix4&) { return FALSE; } // vtable+0x90 virtual MxU32 StepState(float, Matrix4&) { return FALSE; } // vtable+0x90
// FUNCTION: LEGO1 0x10002d50 // FUNCTION: LEGO1 0x10002d50
// FUNCTION: BETA10 0x1000f800 // FUNCTION: BETA10 0x1000f800
@ -93,16 +97,16 @@ class LegoPathActor : public LegoActor {
virtual void SwitchBoundary( virtual void SwitchBoundary(
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
float& p_unk0xe4 float& p_scale
); // vtable+0x98 ); // vtable+0x98
virtual MxResult VTable0x9c(); // vtable+0x9c virtual MxResult CalculateSpline(); // vtable+0x9c
// FUNCTION: LEGO1 0x10002d60 // FUNCTION: LEGO1 0x10002d60
// FUNCTION: BETA10 0x1000f820 // FUNCTION: BETA10 0x1000f820
virtual MxS32 NextTargetLocation() { return 0; } // vtable+0xa0 virtual MxS32 NextTargetLocation() { return 0; } // vtable+0xa0
virtual void VTable0xa4(MxBool& p_und1, MxS32& p_und2); // vtable+0xa4 virtual void GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex); // vtable+0xa4
virtual void VTable0xa8(); // vtable+0xa8 virtual void ApplyLocal2World(); // vtable+0xa8
// FUNCTION: LEGO1 0x10002d70 // FUNCTION: LEGO1 0x10002d70
// FUNCTION: BETA10 0x1000f580 // FUNCTION: BETA10 0x1000f580
@ -114,26 +118,32 @@ class LegoPathActor : public LegoActor {
// FUNCTION: LEGO1 0x10002d90 // FUNCTION: LEGO1 0x10002d90
// FUNCTION: BETA10 0x1000f5e0 // FUNCTION: BETA10 0x1000f5e0
virtual MxFloat VTable0xb4() { return m_unk0x140; } // vtable+0xb4 virtual MxFloat GetWallHitDirectionFactor() { return m_wallHitDirectionFactor; } // vtable+0xb4
// FUNCTION: LEGO1 0x10002da0 // FUNCTION: LEGO1 0x10002da0
// FUNCTION: BETA10 0x1000f610 // FUNCTION: BETA10 0x1000f610
virtual MxFloat VTable0xb8() { return m_unk0x144; } // vtable+0xb8 virtual MxFloat GetWallHitDampening() { return m_wallHitDampening; } // vtable+0xb8
// FUNCTION: LEGO1 0x10002db0 // FUNCTION: LEGO1 0x10002db0
// FUNCTION: BETA10 0x1000f640 // FUNCTION: BETA10 0x1000f640
virtual void VTable0xbc(MxFloat p_unk0x140) { m_unk0x140 = p_unk0x140; } // vtable+0xbc virtual void SetWallHitDirectionFactor(MxFloat p_wallHitDirectionFactor)
{
m_wallHitDirectionFactor = p_wallHitDirectionFactor;
} // vtable+0xbc
// FUNCTION: LEGO1 0x10002dc0 // FUNCTION: LEGO1 0x10002dc0
// FUNCTION: BETA10 0x1000f670 // FUNCTION: BETA10 0x1000f670
virtual void VTable0xc0(MxFloat p_unk0x144) { m_unk0x144 = p_unk0x144; } // vtable+0xc0 virtual void SetWallHitDampening(MxFloat p_wallHitDampening)
{
m_wallHitDampening = p_wallHitDampening;
} // vtable+0xc0
// FUNCTION: LEGO1 0x10002dd0 // FUNCTION: LEGO1 0x10002dd0
// FUNCTION: BETA10 0x1000f6a0 // FUNCTION: BETA10 0x1000f6a0
virtual void VTable0xc4() {} // vtable+0xc4 virtual void VTable0xc4() {} // vtable+0xc4
// FUNCTION: LEGO1 0x10002de0 // FUNCTION: LEGO1 0x10002de0
virtual void VTable0xc8(MxU8 p_unk0x148) { m_unk0x148 = p_unk0x148; } // vtable+0xc8 virtual void SetCanRotate(MxU8 p_canRotate) { m_canRotate = p_canRotate; } // vtable+0xc8
// FUNCTION: LEGO1 0x1000c430 // FUNCTION: LEGO1 0x1000c430
// FUNCTION: BETA10 0x10012790 // FUNCTION: BETA10 0x10012790
@ -158,7 +168,7 @@ class LegoPathActor : public LegoActor {
LegoPathController* GetController() { return m_pathController; } LegoPathController* GetController() { return m_pathController; }
MxBool GetCollideBox() { return m_collideBox; } MxBool GetCollideBox() { return m_collideBox; }
MxFloat GetLastTime() { return m_lastTime; } MxFloat GetTransformTime() { return m_transformTime; }
MxFloat GetActorTime() { return m_actorTime; } MxFloat GetActorTime() { return m_actorTime; }
void SetBoundary(LegoPathBoundary* p_boundary) { m_boundary = p_boundary; } void SetBoundary(LegoPathBoundary* p_boundary) { m_boundary = p_boundary; }
@ -167,7 +177,7 @@ class LegoPathActor : public LegoActor {
void SetActorState(MxU32 p_actorState) { m_actorState = p_actorState; } void SetActorState(MxU32 p_actorState) { m_actorState = p_actorState; }
void SetController(LegoPathController* p_pathController) { m_pathController = p_pathController; } void SetController(LegoPathController* p_pathController) { m_pathController = p_pathController; }
void SetLastTime(MxFloat p_lastTime) { m_lastTime = p_lastTime; } void SetTransformTime(MxFloat p_transformTime) { m_transformTime = p_transformTime; }
void SetActorTime(MxFloat p_actorTime) { m_actorTime = p_actorTime; } void SetActorTime(MxFloat p_actorTime) { m_actorTime = p_actorTime; }
void UpdatePlane(LegoNamedPlane& p_namedPlane); void UpdatePlane(LegoNamedPlane& p_namedPlane);
@ -178,42 +188,42 @@ class LegoPathActor : public LegoActor {
// LegoPathActor::`scalar deleting destructor' // LegoPathActor::`scalar deleting destructor'
protected: protected:
inline MxU32 FUN_1002edd0( inline MxU32 CheckIntersectionBothFaces(
list<LegoPathBoundary*>& p_boundaries, list<LegoPathBoundary*>& p_checkedBoundaries,
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3, Vector3& p_intersectionPoint,
MxS32 p_und MxS32 p_depth
); );
MxFloat m_BADuration; // 0x78 MxFloat m_BADuration; // 0x78
MxFloat m_unk0x7c; // 0x7c MxFloat m_traveledDistance; // 0x7c
MxFloat m_actorTime; // 0x80 MxFloat m_actorTime; // 0x80
MxFloat m_lastTime; // 0x84 MxFloat m_transformTime; // 0x84
LegoPathBoundary* m_boundary; // 0x88 LegoPathBoundary* m_boundary; // 0x88
LegoUnknown m_unk0x8c; // 0x8c LegoSpline m_spline; // 0x8c
MxU32 m_actorState; // 0xdc MxU32 m_actorState; // 0xdc
LegoOrientedEdge* m_destEdge; // 0xe0 LegoOrientedEdge* m_destEdge; // 0xe0
MxFloat m_unk0xe4; // 0xe4 MxFloat m_destScale; // 0xe4
MxBool m_collideBox; // 0xe8 MxBool m_collideBox; // 0xe8
MxBool m_unk0xe9; // 0xe9 MxBool m_finishedTravel; // 0xe9
MxBool m_userNavFlag; // 0xea MxBool m_userNavFlag; // 0xea
MxMatrix m_unk0xec; // 0xec MxMatrix m_local2World; // 0xec
LegoPathEdgeContainer* m_grec; // 0x134 LegoPathEdgeContainer* m_grec; // 0x134
LegoPathController* m_pathController; // 0x138 LegoPathController* m_pathController; // 0x138
MxFloat m_maxLinearVel; // 0x13c MxFloat m_maxLinearVel; // 0x13c
MxFloat m_unk0x140; // 0x140 MxFloat m_wallHitDirectionFactor; // 0x140
MxFloat m_unk0x144; // 0x144 MxFloat m_wallHitDampening; // 0x144
MxU8 m_unk0x148; // 0x148 MxU8 m_canRotate; // 0x148
MxS32 m_unk0x14c; // 0x14c MxS32 m_lastRotationAngle; // 0x14c
MxFloat m_unk0x150; // 0x150 MxFloat m_linearRotationRatio; // 0x150
}; };
// FUNCTION: LEGO1 0x1002edd0 // FUNCTION: LEGO1 0x1002edd0
// LegoPathActor::FUN_1002edd0 // LegoPathActor::CheckIntersectionBothFaces
// TEMPLATE: LEGO1 0x10018b70 // TEMPLATE: LEGO1 0x10018b70
// List<LegoBoundaryEdge>::~List<LegoBoundaryEdge> // List<LegoBoundaryEdge>::~List<LegoBoundaryEdge>

View File

@ -40,14 +40,20 @@ class LegoPathBoundary : public LegoWEGEdge {
MxResult AddActor(LegoPathActor* p_actor); MxResult AddActor(LegoPathActor* p_actor);
MxResult RemoveActor(LegoPathActor* p_actor); MxResult RemoveActor(LegoPathActor* p_actor);
void CheckAndCallPathTriggers(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor); void CheckAndCallPathTriggers(Vector3& p_from, Vector3& p_to, LegoPathActor* p_actor);
void SwitchBoundary( void SwitchBoundary(
LegoPathActor* p_actor, LegoPathActor* p_actor,
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
float& p_unk0xe4 float& p_scale
);
MxU32 Intersect(
float p_scale,
Vector3& p_oldPos,
Vector3& p_newPos,
Vector3& p_intersectionPoint,
LegoOrientedEdge*& p_edge
); );
MxU32 Intersect(float p_scale, Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, LegoOrientedEdge*& p_edge);
MxU32 AddPresenterIfInRange(LegoAnimPresenter* p_presenter); MxU32 AddPresenterIfInRange(LegoAnimPresenter* p_presenter);
MxU32 RemovePresenter(LegoAnimPresenter* p_presenter); MxU32 RemovePresenter(LegoAnimPresenter* p_presenter);

View File

@ -109,13 +109,13 @@ class LegoPathController : public MxCore {
); );
MxResult PlaceActor(LegoPathActor* p_actor); MxResult PlaceActor(LegoPathActor* p_actor);
MxResult RemoveActor(LegoPathActor* p_actor); MxResult RemoveActor(LegoPathActor* p_actor);
void FUN_100468f0(LegoAnimPresenter* p_presenter); void AddPresenterIfInRange(LegoAnimPresenter* p_presenter);
void RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter); void RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter);
MxResult FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL); MxResult GetBoundaries(LegoPathBoundary*& p_boundaries, MxS32& p_numL);
LegoPathBoundary* GetPathBoundary(const char* p_name); LegoPathBoundary* GetPathBoundary(const char* p_name);
void Enable(MxBool p_enable); void Enable(MxBool p_enable);
void FUN_10046bb0(LegoWorld* p_world); void SetWorld(LegoWorld* p_world);
MxResult FUN_10048310( MxResult FindPath(
LegoPathEdgeContainer* p_grec, LegoPathEdgeContainer* p_grec,
const Vector3& p_oldPosition, const Vector3& p_oldPosition,
const Vector3& p_oldDirection, const Vector3& p_oldDirection,
@ -124,17 +124,17 @@ class LegoPathController : public MxCore {
const Vector3& p_newDirection, const Vector3& p_newDirection,
LegoPathBoundary* p_newBoundary, LegoPathBoundary* p_newBoundary,
LegoU8 p_mask, LegoU8 p_mask,
MxFloat* p_param9 MxFloat* p_distance
); );
MxS32 FUN_1004a240( MxS32 GetNextPathEdge(
LegoPathEdgeContainer& p_grec, LegoPathEdgeContainer& p_grec,
Vector3& p_v1, Vector3& p_position,
Vector3& p_v2, Vector3& p_direction,
float p_f1, float p_f1,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
LegoPathBoundary*& p_boundary LegoPathBoundary*& p_boundary
); );
MxResult FUN_1004a380( MxResult FindIntersectionBoundary(
Vector3& p_param1, Vector3& p_param1,
Vector3& p_param2, Vector3& p_param2,
Mx3DPointFloat* p_param3, Mx3DPointFloat* p_param3,
@ -159,7 +159,7 @@ class LegoPathController : public MxCore {
static LegoPathBoundary* GetControlBoundaryB(MxS32 p_index) { return g_ctrlBoundariesB[p_index].m_boundary; } static LegoPathBoundary* GetControlBoundaryB(MxS32 p_index) { return g_ctrlBoundariesB[p_index].m_boundary; }
private: private:
void FUN_10046970(); void AnimateActors();
MxResult Read(LegoStorage* p_storage); MxResult Read(LegoStorage* p_storage);
MxResult ReadStructs(LegoStorage* p_storage); MxResult ReadStructs(LegoStorage* p_storage);
MxResult ReadEdges(LegoStorage* p_storage); MxResult ReadEdges(LegoStorage* p_storage);
@ -179,7 +179,7 @@ class LegoPathController : public MxCore {
} }
// FUNCTION: BETA10 0x100c17a0 // FUNCTION: BETA10 0x100c17a0
static MxU32 FUN_100c17a0(MxFloat p_v1, MxFloat p_v2, MxFloat p_a, MxFloat p_b) static MxU32 BothSameComparison(MxFloat p_v1, MxFloat p_v2, MxFloat p_a, MxFloat p_b)
{ {
assert(IsBetween(p_v1, p_a, p_b)); assert(IsBetween(p_v1, p_a, p_b));
assert(IsBetween(p_v2, p_a, p_b)); assert(IsBetween(p_v2, p_a, p_b));
@ -207,8 +207,8 @@ class LegoPathController : public MxCore {
static CtrlBoundary* g_ctrlBoundariesA; static CtrlBoundary* g_ctrlBoundariesA;
static CtrlEdge* g_ctrlEdgesA; static CtrlEdge* g_ctrlEdgesA;
static const char* g_unk0x100f42f0[]; static const char* g_ctrlBoundariesNamesA[];
static const char* g_unk0x100f4330[]; static const char* g_ctrlBoundariesNamesB[];
static CtrlBoundary* g_ctrlBoundariesB; static CtrlBoundary* g_ctrlBoundariesB;
static CtrlEdge* g_ctrlEdgesB; static CtrlEdge* g_ctrlEdgesB;
}; };
@ -296,58 +296,58 @@ class LegoPathController : public MxCore {
// _Tree<LegoPathCtrlEdge *,LegoPathCtrlEdge *,set<LegoPathCtrlEdge *,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Kfn,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Ubound // _Tree<LegoPathCtrlEdge *,LegoPathCtrlEdge *,set<LegoPathCtrlEdge *,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Kfn,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Ubound
// TEMPLATE: LEGO1 0x100493a0 // TEMPLATE: LEGO1 0x100493a0
// list<LegoBEWithFloat,allocator<LegoBEWithFloat> >::~list<LegoBEWithFloat,allocator<LegoBEWithFloat> > // list<LegoBEWithMidpoint,allocator<LegoBEWithMidpoint> >::~list<LegoBEWithMidpoint,allocator<LegoBEWithMidpoint> >
// TEMPLATE: LEGO1 0x10049410 // TEMPLATE: LEGO1 0x10049410
// list<LegoBEWithFloat,allocator<LegoBEWithFloat> >::insert // list<LegoBEWithMidpoint,allocator<LegoBEWithMidpoint> >::insert
// TEMPLATE: LEGO1 0x10049470 // TEMPLATE: LEGO1 0x10049470
// list<LegoBEWithFloat,allocator<LegoBEWithFloat> >::_Buynode // list<LegoBEWithMidpoint,allocator<LegoBEWithMidpoint> >::_Buynode
// TEMPLATE: LEGO1 0x100494a0 // TEMPLATE: LEGO1 0x100494a0
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::iterator::_Inc // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::iterator::_Inc
// TEMPLATE: LEGO1 0x100494e0 // TEMPLATE: LEGO1 0x100494e0
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::~_Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFlo // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::~_Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithFlo
// TEMPLATE: LEGO1 0x100495b0 // TEMPLATE: LEGO1 0x100495b0
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::insert // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::insert
// TEMPLATE: LEGO1 0x10049840 // TEMPLATE: LEGO1 0x10049840
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::iterator::_Dec // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::iterator::_Dec
// TEMPLATE: LEGO1 0x10049890 // TEMPLATE: LEGO1 0x10049890
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::erase // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::erase
// TEMPLATE: LEGO1 0x10049cf0 // TEMPLATE: LEGO1 0x10049cf0
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Buynode // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Buynode
// TEMPLATE: LEGO1 0x10049d50 // TEMPLATE: LEGO1 0x10049d50
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Init // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Init
// TEMPLATE: LEGO1 0x10049e00 // TEMPLATE: LEGO1 0x10049e00
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Insert // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Insert
// TEMPLATE: LEGO1 0x10049d10 // TEMPLATE: LEGO1 0x10049d10
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Erase // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Erase
// TEMPLATE: LEGO1 0x1004a090 // TEMPLATE: LEGO1 0x1004a090
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Lrotate // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Lrotate
// TEMPLATE: LEGO1 0x1004a0f0 // TEMPLATE: LEGO1 0x1004a0f0
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Rrotate // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Rrotate
// TEMPLATE: LEGO1 0x1004a150 // TEMPLATE: LEGO1 0x1004a150
// List<LegoBEWithFloat>::~List<LegoBEWithFloat> // List<LegoBEWithMidpoint>::~List<LegoBEWithMidpoint>
// TEMPLATE: LEGO1 0x1004a1a0 // TEMPLATE: LEGO1 0x1004a1a0
// Multiset<LegoBEWithFloat *,LegoBEWithFloatComparator>::~Multiset<LegoBEWithFloat *,LegoBEWithFloatComparator> // Multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator>::~Multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator>
// TEMPLATE: LEGO1 0x1004a1f0 // TEMPLATE: LEGO1 0x1004a1f0
// multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::~multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> > // multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::~multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >
// TEMPLATE: LEGO1 0x1004a760 // TEMPLATE: LEGO1 0x1004a760
// ?_Construct@@YAXPAPAULegoBEWithFloat@@ABQAU1@@Z // ?_Construct@@YAXPAPAULegoBEWithMidpoint@@ABQAU1@@Z
// TEMPLATE: LEGO1 0x1004a780 // TEMPLATE: LEGO1 0x1004a780
// ?_Construct@@YAXPAPAULegoPathCtrlEdge@@ABQAU1@@Z // ?_Construct@@YAXPAPAULegoPathCtrlEdge@@ABQAU1@@Z
@ -356,7 +356,7 @@ class LegoPathController : public MxCore {
// _Tree<LegoPathCtrlEdge *,LegoPathCtrlEdge *,set<LegoPathCtrlEdge *,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Kfn,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Nil // _Tree<LegoPathCtrlEdge *,LegoPathCtrlEdge *,set<LegoPathCtrlEdge *,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Kfn,LegoPathCtrlEdgeCompare,allocator<LegoPathCtrlEdge *> >::_Nil
// GLOBAL: LEGO1 0x100f4364 // GLOBAL: LEGO1 0x100f4364
// _Tree<LegoBEWithFloat *,LegoBEWithFloat *,multiset<LegoBEWithFloat *,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Kfn,LegoBEWithFloatComparator,allocator<LegoBEWithFloat *> >::_Nil // _Tree<LegoBEWithMidpoint *,LegoBEWithMidpoint *,multiset<LegoBEWithMidpoint *,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Kfn,LegoBEWithMidpointComparator,allocator<LegoBEWithMidpoint *> >::_Nil
// clang-format on // clang-format on
#endif // LEGOPATHCONTROLLER_H #endif // LEGOPATHCONTROLLER_H

View File

@ -27,56 +27,61 @@ struct LegoBoundaryEdge {
}; };
// SIZE 0x10 // SIZE 0x10
struct LegoBEWithFloat { struct LegoBEWithMidpoint {
LegoBEWithFloat() LegoBEWithMidpoint()
{ {
m_edge = NULL; m_edge = NULL;
m_boundary = NULL; m_boundary = NULL;
m_next = NULL; m_next = NULL;
m_unk0x0c = 0.0f; m_distanceToMidpoint = 0.0f;
} }
// FUNCTION: BETA10 0x100bd9a0 // FUNCTION: BETA10 0x100bd9a0
LegoBEWithFloat(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, MxFloat p_unk0x0c) LegoBEWithMidpoint(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, MxFloat p_distanceToMidpoint)
{ {
m_edge = p_edge; m_edge = p_edge;
m_boundary = p_boundary; m_boundary = p_boundary;
m_next = NULL; m_next = NULL;
m_unk0x0c = p_unk0x0c; m_distanceToMidpoint = p_distanceToMidpoint;
} }
// FUNCTION: BETA10 0x100bd9f0 // FUNCTION: BETA10 0x100bd9f0
LegoBEWithFloat(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, LegoBEWithFloat* p_next, MxFloat p_unk0x0c) LegoBEWithMidpoint(
LegoPathCtrlEdge* p_edge,
LegoPathBoundary* p_boundary,
LegoBEWithMidpoint* p_next,
MxFloat p_distanceToMidpoint
)
{ {
m_edge = p_edge; m_edge = p_edge;
m_boundary = p_boundary; m_boundary = p_boundary;
m_next = p_next; m_next = p_next;
m_unk0x0c = p_unk0x0c; m_distanceToMidpoint = p_distanceToMidpoint;
} }
LegoPathCtrlEdge* m_edge; // 0x00 LegoPathCtrlEdge* m_edge; // 0x00
LegoPathBoundary* m_boundary; // 0x04 LegoPathBoundary* m_boundary; // 0x04
LegoBEWithFloat* m_next; // 0x08 LegoBEWithMidpoint* m_next; // 0x08
MxFloat m_unk0x0c; // 0x0c MxFloat m_distanceToMidpoint; // 0x0c
int operator==(LegoBEWithFloat) const { return 0; } int operator==(LegoBEWithMidpoint) const { return 0; }
int operator<(LegoBEWithFloat) const { return 0; } int operator<(LegoBEWithMidpoint) const { return 0; }
}; };
struct LegoBEWithFloatComparator { struct LegoBEWithMidpointComparator {
// FUNCTION: BETA10 0x100bef80 // FUNCTION: BETA10 0x100bef80
bool operator()(LegoBEWithFloat* const& p_a, LegoBEWithFloat* const& p_b) const bool operator()(LegoBEWithMidpoint* const& p_a, LegoBEWithMidpoint* const& p_b) const
{ {
return p_a->m_unk0x0c < p_b->m_unk0x0c; return p_a->m_distanceToMidpoint < p_b->m_distanceToMidpoint;
} }
}; };
typedef multiset<LegoBEWithFloat*, LegoBEWithFloatComparator> LegoBEWithFloatSet; typedef multiset<LegoBEWithMidpoint*, LegoBEWithMidpointComparator> LegoBEWithMidpointSet;
// SIZE 0x3c // SIZE 0x3c
struct LegoPathEdgeContainer : public list<LegoBoundaryEdge> { struct LegoPathEdgeContainer : public list<LegoBoundaryEdge> {
enum { enum {
c_bit1 = 0x01 c_hasPath = 0x01
}; };
// FUNCTION: BETA10 0x100118e0 // FUNCTION: BETA10 0x100118e0
@ -87,18 +92,18 @@ struct LegoPathEdgeContainer : public list<LegoBoundaryEdge> {
} }
// FUNCTION: BETA10 0x100bd660 // FUNCTION: BETA10 0x100bd660
void SetBit1(MxU32 p_set) void SetPath(MxU32 p_set)
{ {
if (p_set) { if (p_set) {
m_flags |= c_bit1; m_flags |= c_hasPath;
} }
else { else {
m_flags &= ~c_bit1; m_flags &= ~c_hasPath;
} }
} }
// FUNCTION: BETA10 0x1001cb50 // FUNCTION: BETA10 0x1001cb50
MxU32 GetBit1() { return m_flags & c_bit1; } MxU32 HasPath() { return m_flags & c_hasPath; }
Mx3DPointFloat m_position; // 0x0c Mx3DPointFloat m_position; // 0x0c
Mx3DPointFloat m_direction; // 0x20 Mx3DPointFloat m_direction; // 0x20

View File

@ -30,9 +30,13 @@ class LegoRaceActor : public virtual LegoAnimActor {
return !strcmp(p_name, LegoRaceActor::ClassName()) || LegoAnimActor::IsA(p_name); return !strcmp(p_name, LegoRaceActor::ClassName()) || LegoAnimActor::IsA(p_name);
} }
MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override; // vtable+0x68 MxS32 CheckIntersections(
MxU32 VTable0x90(float p_time, Matrix4& p_matrix) override; // vtable+0x90 Vector3& p_rayOrigin,
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 Vector3& p_rayEnd,
Vector3& p_intersectionPoint
) override; // vtable+0x68
MxU32 StepState(float p_time, Matrix4& p_matrix) override; // vtable+0x90
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
virtual MxResult FUN_10014aa0(); virtual MxResult FUN_10014aa0();

View File

@ -26,7 +26,7 @@ class LegoRaceMap : public virtual LegoRaceActor {
void Animate(float p_time) override = 0; // vtable+0x70 void Animate(float p_time) override = 0; // vtable+0x70
// LegoRaceMap vtable // LegoRaceMap vtable
virtual void FUN_1005d4b0(); // vtable+0x00 virtual void UpdateMapLocatorPosition(); // vtable+0x00
// SYNTHETIC: LEGO1 0x10012c50 // SYNTHETIC: LEGO1 0x10012c50
// LegoRaceMap::`vbase destructor' // LegoRaceMap::`vbase destructor'
@ -35,28 +35,28 @@ class LegoRaceMap : public virtual LegoRaceActor {
// LegoRaceMap::`scalar deleting destructor' // LegoRaceMap::`scalar deleting destructor'
private: private:
MxBool m_unk0x08; // 0x08 MxBool m_mapEnabled; // 0x08
MxStillPresenter* m_stillPresenter; // 0x0c MxStillPresenter* m_stillPresenter; // 0x0c
// variable name verified by BETA10 0x100ca82b // variable name verified by BETA10 0x100ca82b
MxControlPresenter* m_Map_Ctl; // 0x10 MxControlPresenter* m_Map_Ctl; // 0x10
// likely an x-offset of the race map in world space // likely an x-offset of the race map in world space
float m_unk0x14; // 0x14 float m_worldXOffset; // 0x14
// inversely scales the map in x direction (either convert world->screen space or to control the size) // inversely scales the map in x direction (either convert world->screen space or to control the size)
float m_unk0x18; // 0x18 float m_worldXScale; // 0x18
// likely a y-offset of the race map in world space // likely a z-offset of the race map in world space
float m_unk0x1c; // 0x1c float m_worldZOffset; // 0x1c
// inversely scales the map in y direction (either convert world->screen space or to control the size) // inversely scales the map in z direction (either convert world->screen space or to control the size)
float m_unk0x20; // 0x20 float m_worldZScale; // 0x20
// scales the map in x direction (either convert world->screen space or to change the size) // scales the map in x direction (either convert world->screen space or to change the size)
float m_unk0x24; // 0x24 float m_screenXScale; // 0x24
// scales the map in y direction (either convert world->screen space or to change the size) // scales the map in y direction (either convert world->screen space or to change the size)
float m_unk0x28; // 0x28 float m_screenYScale; // 0x28
// likely an x-offset of the race map in screen space // likely an x-offset of the race map in screen space
float m_unk0x2c; // 0x2c float m_screenXOffset; // 0x2c
// likely a y-offset of the race map in screen space // likely a y-offset of the race map in screen space
float m_unk0x30; // 0x30 float m_screenYOffset; // 0x30
}; };
// GLOBAL: LEGO1 0x100d8848 // GLOBAL: LEGO1 0x100d8848

View File

@ -6,9 +6,11 @@
// clang-format on // clang-format on
#include "legoracemap.h" #include "legoracemap.h"
#define LEGORACECAR_UNKNOWN_0 0 #define LEGORACECAR_NONE 0
#define LEGORACECAR_UNKNOWN_1 1 #define LEGORACECAR_NEAR_SKELETON 1
// kick to the left
#define LEGORACECAR_KICK1 2 // name guessed #define LEGORACECAR_KICK1 2 // name guessed
// kick to the right
#define LEGORACECAR_KICK2 4 // name validated by BETA10 0x100cb659 #define LEGORACECAR_KICK2 4 // name validated by BETA10 0x100cb659
// SIZE 0x08 // SIZE 0x08
@ -23,7 +25,7 @@ struct SkeletonKickPhase {
EdgeReference* m_edgeRef; // 0x00 EdgeReference* m_edgeRef; // 0x00
float m_lower; // 0x04 float m_lower; // 0x04
float m_upper; // 0x08 float m_upper; // 0x08
MxU8 m_userState; // 0x0c MxU8 m_kickState; // 0x0c
}; };
// VTABLE: LEGO1 0x100d5a08 LegoCarRaceActor // VTABLE: LEGO1 0x100d5a08 LegoCarRaceActor
@ -62,10 +64,23 @@ class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap {
void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30
// FUNCTION: LEGO1 0x10014150 // FUNCTION: LEGO1 0x10014150
MxU32 VTable0x6c(LegoPathBoundary* p_boundary, Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) MxU32 CheckPresenterAndActorIntersections(
override LegoPathBoundary* p_boundary,
Vector3& p_rayOrigin,
Vector3& p_rayDirection,
float p_rayLength,
float p_radius,
Vector3& p_intersectionPoint
) override
{ {
return LegoJetskiRaceActor::VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); return LegoJetskiRaceActor::CheckPresenterAndActorIntersections(
p_boundary,
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint
);
} // vtable+0x6c } // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
@ -78,9 +93,9 @@ class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap {
} // vtable+0x98 } // vtable+0x98
// FUNCTION: LEGO1 0x10014210 // FUNCTION: LEGO1 0x10014210
MxResult VTable0x9c() override { return LegoJetskiRaceActor::VTable0x9c(); } // vtable+0x9c MxResult CalculateSpline() override { return LegoJetskiRaceActor::CalculateSpline(); } // vtable+0x9c
virtual void FUN_100136f0(float p_worldSpeed); virtual void SetMaxLinearVelocity(float p_worldSpeed);
static void InitSoundIndices(); static void InitSoundIndices();
@ -125,10 +140,23 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
// FUNCTION: LEGO1 0x10014500 // FUNCTION: LEGO1 0x10014500
// FUNCTION: BETA10 0x100cd5e0 // FUNCTION: BETA10 0x100cd5e0
MxU32 VTable0x6c(LegoPathBoundary* p_boundary, Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) MxU32 CheckPresenterAndActorIntersections(
override LegoPathBoundary* p_boundary,
Vector3& p_rayOrigin,
Vector3& p_rayDirection,
float p_rayLength,
float p_radius,
Vector3& p_intersectionPoint
) override
{ {
return LegoCarRaceActor::VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); return LegoCarRaceActor::CheckPresenterAndActorIntersections(
p_boundary,
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint
);
} // vtable+0x6c } // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
@ -141,7 +169,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
LegoCarRaceActor::SwitchBoundary(p_boundary, p_edge, p_unk0xe4); LegoCarRaceActor::SwitchBoundary(p_boundary, p_edge, p_unk0xe4);
} // vtable+0x98 } // vtable+0x98
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
virtual void SetMaxLinearVelocity(float p_maxLinearVelocity); virtual void SetMaxLinearVelocity(float p_maxLinearVelocity);
virtual void KickCamera(float p_param); virtual void KickCamera(float p_param);
@ -154,7 +182,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
// LegoRaceCar::`scalar deleting destructor' // LegoRaceCar::`scalar deleting destructor'
private: private:
undefined m_userState; // 0x54 MxU8 m_kickState; // 0x54
float m_kickStart; // 0x58 float m_kickStart; // 0x58
Mx3DPointFloat m_unk0x5c; // 0x5c Mx3DPointFloat m_unk0x5c; // 0x5c

View File

@ -35,21 +35,21 @@ class LegoCarRaceActor : public virtual LegoRaceActor {
return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoRaceActor::IsA(p_name); return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoRaceActor::IsA(p_name);
} }
MxU32 VTable0x6c( MxU32 CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) override; // vtable+0x6c ) override; // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
void SwitchBoundary( void SwitchBoundary(
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
float& p_unk0xe4 float& p_unk0xe4
) override; // vtable+0x98 ) override; // vtable+0x98
MxResult VTable0x9c() override; // vtable+0x9c MxResult CalculateSpline() override; // vtable+0x9c
// LegoCarRaceActor vtable // LegoCarRaceActor vtable
@ -130,13 +130,13 @@ class LegoJetskiRaceActor : public virtual LegoCarRaceActor {
return !strcmp(p_name, LegoJetskiRaceActor::ClassName()) || LegoCarRaceActor::IsA(p_name); return !strcmp(p_name, LegoJetskiRaceActor::ClassName()) || LegoCarRaceActor::IsA(p_name);
} }
MxU32 VTable0x6c( MxU32 CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) override; // vtable+0x6c ) override; // vtable+0x6c
void Animate(float p_time) override; // vtable+0x70 void Animate(float p_time) override; // vtable+0x70
MxS32 VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge) override; // vtable+0x1c MxS32 VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge) override; // vtable+0x1c

View File

@ -0,0 +1,44 @@
#ifndef LEGOTESTTIMER_H
#define LEGOTESTTIMER_H
#include "decomp.h"
#include "misc/legotypes.h"
#include "mxcore.h"
#include "mxparam.h"
// VTABLE: BETA10 0x101bed08
// SIZE 0x24
class LegoTestTimer : public MxCore {
public:
LegoTestTimer(LegoS32 p_numTimers, LegoS32 p_interval, LegoS32 p_numBins, LegoS32 p_type);
~LegoTestTimer() override; // vtable+00
MxLong Notify(MxParam& p_param) override; // vtable+04
// FUNCTION: BETA10 0x100d18e0
static const char* HandlerClassName() { return "LegoTestTimer"; }
// FUNCTION: BETA10 0x100d18b0
const char* ClassName() const override // vtable+0c
{
return HandlerClassName();
}
void Tick(LegoS32 p_timer);
void ResetAtNextTick();
void Print();
// SYNTHETIC: BETA10 0x100d1900
// LegoTestTimer::`scalar deleting destructor'
private:
LegoS32** m_timers; // 0x08
LegoS32* m_lastTime; // 0x0c
LegoS32* m_totalTime; // 0x10
LegoS32 m_numTimers; // 0x14
LegoS32 m_numBins; // 0x18
LegoS32 m_interval; // 0x1c
MxBool m_enable; // 0x20
MxBool m_keyRegistered; // 0x21
};
#endif // LEGOTESTTIMER_H

View File

@ -43,7 +43,7 @@ class LegoWorldPresenter : public LegoEntityPresenter {
void StartingTickle() override; // vtable+0x1c void StartingTickle() override; // vtable+0x1c
void ParseExtra() override; // vtable+0x30 void ParseExtra() override; // vtable+0x30
MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c
void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 void AdvanceSerialAction(MxPresenter* p_presenter) override; // vtable+0x60
MxResult LoadWorld(char* p_worldName, LegoWorld* p_world); MxResult LoadWorld(char* p_worldName, LegoWorld* p_world);

View File

@ -32,8 +32,8 @@ class MxCompositeMediaPresenter : public MxCompositePresenter {
MxResult PutData() override; // vtable+0x4c MxResult PutData() override; // vtable+0x4c
private: private:
MxS16 m_unk0x4c; // 0x4c MxS16 m_remainingChildren; // 0x4c
MxBool m_unk0x4e; // 0x4e MxBool m_allChildrenStreaming; // 0x4e
}; };
// SYNTHETIC: LEGO1 0x10074000 // SYNTHETIC: LEGO1 0x10074000

View File

@ -18,7 +18,7 @@ class MxControlPresenter : public MxCompositePresenter {
void RepeatingTickle() override {} // vtable+0x24 void RepeatingTickle() override {} // vtable+0x24
// FUNCTION: LEGO1 0x10043fe0 // FUNCTION: LEGO1 0x10043fe0
MxBool VTable0x64(undefined4 p_undefined) override { return m_unk0x50; } // vtable+0x64 MxBool GetActionEnded(undefined4 p_undefined) override { return m_unk0x50; } // vtable+0x64
// FUNCTION: LEGO1 0x10043ff0 // FUNCTION: LEGO1 0x10043ff0
virtual void VTable0x68(MxBool p_unk0x50) { m_unk0x50 = p_unk0x50; } // vtable+0x68 virtual void VTable0x68(MxBool p_unk0x50) { m_unk0x50 = p_unk0x50; } // vtable+0x68

View File

@ -179,9 +179,9 @@ MxResult Act2Actor::HitActor(LegoPathActor*, MxBool)
} }
// FUNCTION: LEGO1 0x10018a20 // FUNCTION: LEGO1 0x10018a20
MxResult Act2Actor::VTable0x9c() MxResult Act2Actor::CalculateSpline()
{ {
if (m_grec && !m_grec->GetBit1()) { if (m_grec && !m_grec->HasPath()) {
delete m_grec; delete m_grec;
m_grec = NULL; m_grec = NULL;
return SUCCESS; return SUCCESS;
@ -198,7 +198,7 @@ MxResult Act2Actor::VTable0x9c()
brickstrROI->UpdateTransformationRelativeToParent(brickstrMatrix); brickstrROI->UpdateTransformationRelativeToParent(brickstrMatrix);
} }
return LegoPathActor::VTable0x9c(); return LegoPathActor::CalculateSpline();
} }
} }
@ -410,7 +410,7 @@ void Act2Actor::FindPath(MxU32 p_location)
newDirection = g_brickstrLocations[p_location].m_direction; newDirection = g_brickstrLocations[p_location].m_direction;
LegoPathBoundary* newBoundary = m_pathController->GetPathBoundary(g_brickstrLocations[p_location].m_boundary); LegoPathBoundary* newBoundary = m_pathController->GetPathBoundary(g_brickstrLocations[p_location].m_boundary);
MxResult sts = m_pathController->FUN_10048310( MxResult sts = m_pathController->FindPath(
m_grec, m_grec,
m_roi->GetWorldPosition(), m_roi->GetWorldPosition(),
m_roi->GetWorldDirection(), m_roi->GetWorldDirection(),
@ -607,7 +607,7 @@ MxU32 Act2Actor::UpdateShot(MxFloat p_time)
return FALSE; return FALSE;
} }
m_lastTime = p_time; m_transformTime = p_time;
LegoROI* brickstrROI = FindROI("brickstr"); LegoROI* brickstrROI = FindROI("brickstr");
MxMatrix initialTransform = m_roi->GetLocal2World(); MxMatrix initialTransform = m_roi->GetLocal2World();

View File

@ -101,20 +101,20 @@ Act3Actor::Act3Actor()
// FUNCTION: LEGO1 0x1003fb70 // FUNCTION: LEGO1 0x1003fb70
// FUNCTION: BETA10 0x100180ab // FUNCTION: BETA10 0x100180ab
MxU32 Act3Actor::VTable0x90(float p_time, Matrix4& p_transform) MxU32 Act3Actor::StepState(float p_time, Matrix4& p_transform)
{ {
// Note: Code duplication with LegoExtraActor::VTable0x90 // Note: Code duplication with LegoExtraActor::StepState
switch (m_actorState & c_maxState) { switch (m_actorState & c_maxState) {
case c_initial: case c_initial:
case c_one: case c_ready:
return TRUE; return TRUE;
case c_two: case c_hit:
m_unk0x1c = p_time + 2000.0f; m_unk0x1c = p_time + 2000.0f;
m_actorState = c_three; m_actorState = c_hitAnimation;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
return FALSE; return FALSE;
case c_three: case c_hitAnimation:
assert(!m_userNavFlag); assert(!m_userNavFlag);
Vector3 positionRef(p_transform[3]); Vector3 positionRef(p_transform[3]);
@ -128,10 +128,10 @@ MxU32 Act3Actor::VTable0x90(float p_time, Matrix4& p_transform)
p_transform.RotateX(0.6); p_transform.RotateX(0.6);
positionRef = position; positionRef = position;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
VTable0x74(p_transform); ApplyTransform(p_transform);
return FALSE; return FALSE;
} }
else { else {
@ -167,7 +167,7 @@ MxResult Act3Actor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
roi->SetLocal2World(local2world); roi->SetLocal2World(local2world);
roi->WrappedUpdateWorldData(); roi->WrappedUpdateWorldData();
p_actor->SetActorState(c_two | c_noCollide); p_actor->SetActorState(c_hit | c_noCollide);
} }
return SUCCESS; return SUCCESS;
@ -196,7 +196,7 @@ MxResult Act3Cop::HitActor(LegoPathActor* p_actor, MxBool p_bool)
assert(m_world); assert(m_world);
((Act3*) m_world)->EatDonut(index); ((Act3*) m_world)->EatDonut(index);
m_unk0x20 = m_lastTime + 2000; m_unk0x20 = m_transformTime + 2000;
SetWorldSpeed(6.0); SetWorldSpeed(6.0);
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
@ -285,7 +285,7 @@ void Act3Cop::Animate(float p_time)
{ {
Act3Actor::Animate(p_time); Act3Actor::Animate(p_time);
if (m_unk0x20 > 0.0f && m_unk0x20 < m_lastTime) { if (m_unk0x20 > 0.0f && m_unk0x20 < m_transformTime) {
SetWorldSpeed(2.0f); SetWorldSpeed(2.0f);
m_unk0x20 = -1.0f; m_unk0x20 = -1.0f;
} }
@ -329,7 +329,7 @@ MxResult Act3Cop::FUN_10040360()
LegoPathEdgeContainer* grec = NULL; LegoPathEdgeContainer* grec = NULL;
Act3* a3 = (Act3*) m_world; Act3* a3 = (Act3*) m_world;
MxMatrix local74(m_unk0xec); MxMatrix local74(m_local2World);
Vector3 local2c(local74[3]); Vector3 local2c(local74[3]);
Vector3 local20(local74[2]); Vector3 local20(local74[2]);
@ -346,7 +346,7 @@ MxResult Act3Cop::FUN_10040360()
assert(grec); assert(grec);
MxFloat local34; MxFloat local34;
if (m_pathController->FUN_10048310( if (m_pathController->FindPath(
grec, grec,
local2c, local2c,
local20, local20,
@ -384,7 +384,7 @@ MxResult Act3Cop::FUN_10040360()
MxFloat locald8; MxFloat locald8;
LegoPathEdgeContainer *local138, *local134, *local140, *local13c; // unused LegoPathEdgeContainer *local138, *local134, *local140, *local13c; // unused
if (m_pathController->FUN_10048310( if (m_pathController->FindPath(
r2, r2,
local2c, local2c,
local20, local20,
@ -424,7 +424,7 @@ MxResult Act3Cop::FUN_10040360()
MxFloat local100; MxFloat local100;
LegoPathEdgeContainer *local150, *local14c; // unused LegoPathEdgeContainer *local150, *local14c; // unused
if (m_pathController->FUN_10048310( if (m_pathController->FindPath(
grec, grec,
local2c, local2c,
local20, local20,
@ -457,7 +457,7 @@ MxResult Act3Cop::FUN_10040360()
vecUnk = m_grec->m_position; vecUnk = m_grec->m_position;
m_boundary = m_grec->m_boundary; m_boundary = m_grec->m_boundary;
m_grec->m_direction = m_unk0xec[3]; m_grec->m_direction = m_local2World[3];
m_grec->m_direction -= vecUnk; m_grec->m_direction -= vecUnk;
} }
else { else {
@ -470,7 +470,7 @@ MxResult Act3Cop::FUN_10040360()
local128 = *v2; local128 = *v2;
local128 -= *v1; local128 -= *v1;
local128 *= m_unk0xe4; local128 *= m_destScale;
local128 += *v1; local128 += *v1;
local128 *= -1.0f; local128 *= -1.0f;
local128 += m_grec->m_position; local128 += m_grec->m_position;
@ -485,14 +485,14 @@ MxResult Act3Cop::FUN_10040360()
vecUnk = *v2; vecUnk = *v2;
vecUnk -= *v1; vecUnk -= *v1;
vecUnk *= m_unk0xe4; vecUnk *= m_destScale;
vecUnk += *v1; vecUnk += *v1;
} }
Vector3 v1(m_unk0xec[0]); Vector3 v1(m_local2World[0]);
Vector3 v2(m_unk0xec[1]); Vector3 v2(m_local2World[1]);
Vector3 v3(m_unk0xec[2]); Vector3 v3(m_local2World[2]);
Vector3 v4(m_unk0xec[3]); Vector3 v4(m_local2World[3]);
v3 = v4; v3 = v4;
v3 -= vecUnk; v3 -= vecUnk;
@ -501,7 +501,7 @@ MxResult Act3Cop::FUN_10040360()
v1.Unitize(); v1.Unitize();
v2.EqualsCross(v3, v1); v2.EqualsCross(v3, v1);
VTable0x9c(); CalculateSpline();
} }
return SUCCESS; return SUCCESS;
@ -509,17 +509,17 @@ MxResult Act3Cop::FUN_10040360()
// FUNCTION: LEGO1 0x10040d20 // FUNCTION: LEGO1 0x10040d20
// FUNCTION: BETA10 0x1001942c // FUNCTION: BETA10 0x1001942c
MxResult Act3Cop::VTable0x9c() MxResult Act3Cop::CalculateSpline()
{ {
if (m_grec && !m_grec->GetBit1()) { if (m_grec && !m_grec->HasPath()) {
delete m_grec; delete m_grec;
m_grec = NULL; m_grec = NULL;
m_lastTime = Timer()->GetTime(); m_transformTime = Timer()->GetTime();
FUN_10040360(); FUN_10040360();
return SUCCESS; return SUCCESS;
} }
return Act3Actor::VTable0x9c(); return Act3Actor::CalculateSpline();
} }
// FUNCTION: LEGO1 0x10040e10 // FUNCTION: LEGO1 0x10040e10
@ -571,7 +571,7 @@ void Act3Brickster::ParseAction(char* p_extra)
// FUNCTION: BETA10 0x100197d7 // FUNCTION: BETA10 0x100197d7
void Act3Brickster::Animate(float p_time) void Act3Brickster::Animate(float p_time)
{ {
if (m_lastTime <= m_unk0x20 && m_unk0x20 <= p_time) { if (m_transformTime <= m_unk0x20 && m_unk0x20 <= p_time) {
SetWorldSpeed(5.0f); SetWorldSpeed(5.0f);
} }
@ -619,7 +619,7 @@ void Act3Brickster::Animate(float p_time)
} }
else { else {
MxMatrix local70; MxMatrix local70;
local70 = m_unk0xec; local70 = m_local2World;
Vector3 local14(local70[0]); Vector3 local14(local70[0]);
Vector3 local28(local70[1]); Vector3 local28(local70[1]);
@ -643,7 +643,7 @@ void Act3Brickster::Animate(float p_time)
} }
} }
m_lastTime = p_time; m_transformTime = p_time;
break; break;
case 4: case 4:
assert(m_shootAnim && m_bInfo); assert(m_shootAnim && m_bInfo);
@ -664,7 +664,7 @@ void Act3Brickster::Animate(float p_time)
} }
else { else {
MxMatrix locale4; MxMatrix locale4;
locale4 = m_unk0xec; locale4 = m_local2World;
Vector3 local88(locale4[0]); Vector3 local88(locale4[0]);
Vector3 local9c(locale4[1]); Vector3 local9c(locale4[1]);
@ -690,7 +690,7 @@ void Act3Brickster::Animate(float p_time)
} }
} }
m_lastTime = p_time; m_transformTime = p_time;
break; break;
case 5: case 5:
if (m_grec == NULL) { if (m_grec == NULL) {
@ -794,11 +794,11 @@ MxResult Act3Brickster::FUN_100417c0()
LegoPathEdgeContainer* grec = NULL; LegoPathEdgeContainer* grec = NULL;
Act3* a3 = (Act3*) m_world; Act3* a3 = (Act3*) m_world;
MxMatrix local70(m_unk0xec); MxMatrix local70(m_local2World);
Vector3 local28(local70[3]); Vector3 local28(local70[3]);
Vector3 local20(local70[2]); Vector3 local20(local70[2]);
if (m_unk0x58 < 8 && m_unk0x24 + 5000.0f < m_lastTime) { if (m_unk0x58 < 8 && m_unk0x24 + 5000.0f < m_transformTime) {
float local18; float local18;
for (MxS32 i = 0; i < MAX_PIZZAS; i++) { for (MxS32 i = 0; i < MAX_PIZZAS; i++) {
@ -824,7 +824,7 @@ MxResult Act3Brickster::FUN_100417c0()
MxFloat locald8; MxFloat locald8;
LegoPathEdgeContainer *local16c, *local168, *local174, *local170; // unused LegoPathEdgeContainer *local16c, *local168, *local174, *local170; // unused
if (m_pathController->FUN_10048310( if (m_pathController->FindPath(
r2, r2,
local28, local28,
local20, local20,
@ -908,7 +908,7 @@ MxResult Act3Brickster::FUN_100417c0()
MxFloat local13c; MxFloat local13c;
LegoPathEdgeContainer *local1c0, *local1bc; // unused LegoPathEdgeContainer *local1c0, *local1bc; // unused
if (m_pathController->FUN_10048310( if (m_pathController->FindPath(
grec, grec,
local28, local28,
local20, local20,
@ -951,7 +951,7 @@ MxResult Act3Brickster::FUN_100417c0()
vecUnk = m_grec->m_position; vecUnk = m_grec->m_position;
m_boundary = m_grec->m_boundary; m_boundary = m_grec->m_boundary;
m_grec->m_direction = m_unk0xec[3]; m_grec->m_direction = m_local2World[3];
m_grec->m_direction -= vecUnk; m_grec->m_direction -= vecUnk;
local150 = m_grec->m_direction; local150 = m_grec->m_direction;
@ -965,7 +965,7 @@ MxResult Act3Brickster::FUN_100417c0()
local150 = *v2; local150 = *v2;
local150 -= *v1; local150 -= *v1;
local150 *= m_unk0xe4; local150 *= m_destScale;
local150 += *v1; local150 += *v1;
local150 *= -1.0f; local150 *= -1.0f;
local150 += m_grec->m_position; local150 += m_grec->m_position;
@ -980,14 +980,14 @@ MxResult Act3Brickster::FUN_100417c0()
vecUnk = *v2; vecUnk = *v2;
vecUnk -= *v1; vecUnk -= *v1;
vecUnk *= m_unk0xe4; vecUnk *= m_destScale;
vecUnk += *v1; vecUnk += *v1;
} }
Vector3 v1(m_unk0xec[0]); Vector3 v1(m_local2World[0]);
Vector3 v2(m_unk0xec[1]); Vector3 v2(m_local2World[1]);
Vector3 v3(m_unk0xec[2]); Vector3 v3(m_local2World[2]);
Vector3 v4(m_unk0xec[3]); Vector3 v4(m_local2World[3]);
v3 = v4; v3 = v4;
v3 -= vecUnk; v3 -= vecUnk;
@ -996,7 +996,7 @@ MxResult Act3Brickster::FUN_100417c0()
v1.Unitize(); v1.Unitize();
v2.EqualsCross(v3, v1); v2.EqualsCross(v3, v1);
VTable0x9c(); CalculateSpline();
if (m_pInfo != NULL) { if (m_pInfo != NULL) {
m_unk0x38 = 5; m_unk0x38 = 5;
@ -1099,10 +1099,10 @@ MxS32 Act3Brickster::FUN_10042300()
m_destEdge = maxE; m_destEdge = maxE;
if (m_boundary != boundaries[0]) { if (m_boundary != boundaries[0]) {
m_unk0xe4 = 1.0 - m_unk0xe4; m_destScale = 1.0 - m_destScale;
} }
VTable0x9c(); CalculateSpline();
} }
return -1; return -1;
@ -1119,16 +1119,16 @@ void Act3Brickster::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEd
// FUNCTION: LEGO1 0x100429d0 // FUNCTION: LEGO1 0x100429d0
// FUNCTION: BETA10 0x1001b75b // FUNCTION: BETA10 0x1001b75b
MxResult Act3Brickster::VTable0x9c() MxResult Act3Brickster::CalculateSpline()
{ {
if (m_grec && !m_grec->GetBit1()) { if (m_grec && !m_grec->HasPath()) {
delete m_grec; delete m_grec;
m_grec = NULL; m_grec = NULL;
m_lastTime = Timer()->GetTime(); m_transformTime = Timer()->GetTime();
return SUCCESS; return SUCCESS;
} }
return Act3Actor::VTable0x9c(); return Act3Actor::CalculateSpline();
} }
// FUNCTION: LEGO1 0x10042ab0 // FUNCTION: LEGO1 0x10042ab0
@ -1217,7 +1217,7 @@ void Act3Shark::ParseAction(char* p_extra)
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
presenter->FUN_1006d680(this, atof(token)); presenter->CreateROIAndBuildMap(this, atof(token));
} }
} }

View File

@ -17,7 +17,7 @@ DECOMP_SIZE_ASSERT(Act3Ammo, 0x1a0)
// Initialized at LEGO1 0x100537c0 // Initialized at LEGO1 0x100537c0
// GLOBAL: LEGO1 0x10104f08 // GLOBAL: LEGO1 0x10104f08
Mx3DPointFloat Act3Ammo::g_unk0x10104f08 = Mx3DPointFloat(0.0, 5.0, 0.0); Mx3DPointFloat Act3Ammo::g_hitTranslation = Mx3DPointFloat(0.0, 5.0, 0.0);
// FUNCTION: LEGO1 0x100537f0 // FUNCTION: LEGO1 0x100537f0
// FUNCTION: BETA10 0x1001d648 // FUNCTION: BETA10 0x1001d648
@ -111,43 +111,44 @@ MxResult Act3Ammo::Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index)
// FUNCTION: LEGO1 0x10053b40 // FUNCTION: LEGO1 0x10053b40
// FUNCTION: BETA10 0x1001db2a // FUNCTION: BETA10 0x1001db2a
MxResult Act3Ammo::FUN_10053b40(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp) MxResult Act3Ammo::CalculateArc(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp)
{ {
assert(p_srcDir[1] != 0); assert(p_srcDir[1] != 0);
MxFloat local1c = -(p_srcLoc[1] / p_srcDir[1]); MxFloat yRatioLocDir = -(p_srcLoc[1] / p_srcDir[1]);
Mx3DPointFloat local18(p_srcDir); Mx3DPointFloat groundPoint(p_srcDir);
Mx3DPointFloat local34; Mx3DPointFloat negNormalUp;
local18 *= local1c; groundPoint *= yRatioLocDir;
local18 += p_srcLoc; groundPoint += p_srcLoc;
local34[0] = local34[2] = 0.0f; negNormalUp[0] = negNormalUp[2] = 0.0f;
local34[1] = -1.0f; negNormalUp[1] = -1.0f;
m_eq[1] = p_srcUp; m_coefficients[1] = p_srcUp;
m_eq[2] = p_srcLoc; m_coefficients[2] = p_srcLoc;
Mx3DPointFloat local48(local34); Mx3DPointFloat upRelative(negNormalUp);
local48 -= m_eq[1]; upRelative -= m_coefficients[1];
for (MxS32 i = 0; i < 3; i++) { for (MxS32 i = 0; i < 3; i++) {
if (local18[0] == p_srcLoc[0]) { if (groundPoint[0] == p_srcLoc[0]) {
return FAILURE; return FAILURE;
} }
m_eq[0][i] = (local48[i] * local48[i] + local48[i] * m_eq[1][i] * 2.0f) / ((local18[i] - p_srcLoc[i]) * 4.0f); m_coefficients[0][i] = (upRelative[i] * upRelative[i] + upRelative[i] * m_coefficients[1][i] * 2.0f) /
((groundPoint[i] - p_srcLoc[i]) * 4.0f);
} }
assert(m_eq[0][0] > 0.000001 || m_eq[0][0] < -0.000001); assert(m_coefficients[0][0] > 0.000001 || m_coefficients[0][0] < -0.000001);
m_unk0x19c = local48[0] / (m_eq[0][0] * 2.0f); m_apexParameter = upRelative[0] / (m_coefficients[0][0] * 2.0f);
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x10053cb0 // FUNCTION: LEGO1 0x10053cb0
// FUNCTION: BETA10 0x1001ddf4 // FUNCTION: BETA10 0x1001ddf4
MxResult Act3Ammo::FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_unk0x19c) MxResult Act3Ammo::Shoot(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_apexParameter)
{ {
assert(p_p); assert(p_p);
assert(IsValid()); assert(IsValid());
@ -164,21 +165,21 @@ MxResult Act3Ammo::FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_bou
m_pathController = p_p; m_pathController = p_p;
m_boundary = p_boundary; m_boundary = p_boundary;
m_BADuration = 10000.0f; m_BADuration = 10000.0f;
m_unk0x19c = p_unk0x19c; m_apexParameter = p_apexParameter;
m_unk0x7c = 0.0f; m_traveledDistance = 0.0f;
m_lastTime = -1.0f; m_transformTime = -1.0f;
m_actorState = c_one; m_actorState = c_ready;
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x10053d30 // FUNCTION: LEGO1 0x10053d30
// FUNCTION: BETA10 0x1001df73 // FUNCTION: BETA10 0x1001df73
MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) MxResult Act3Ammo::Shoot(LegoPathController* p_p, MxFloat p_apexParameter)
{ {
assert(p_p); assert(p_p);
assert(IsValid()); assert(IsValid());
SetBit4(TRUE); SetShootWithoutBoundary(TRUE);
if (IsPizza()) { if (IsPizza()) {
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
@ -191,58 +192,58 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c)
m_pathController = p_p; m_pathController = p_p;
m_BADuration = 10000.0f; m_BADuration = 10000.0f;
m_unk0x19c = p_unk0x19c; m_apexParameter = p_apexParameter;
m_unk0x7c = 0.0f; m_traveledDistance = 0.0f;
m_lastTime = -1.0f; m_transformTime = -1.0f;
m_actorState = c_one; m_actorState = c_ready;
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x10053db0 // FUNCTION: LEGO1 0x10053db0
// FUNCTION: BETA10 0x1001e0f0 // FUNCTION: BETA10 0x1001e0f0
MxResult Act3Ammo::FUN_10053db0(float p_param1, Matrix4& p_param2) MxResult Act3Ammo::CalculateTransformOnCurve(float p_curveParameter, Matrix4& p_transform)
{ {
float local34 = p_param1 * p_param1; float curveParameterSquare = p_curveParameter * p_curveParameter;
Vector3 local14(p_param2[0]); Vector3 right(p_transform[0]);
Vector3 local3c(p_param2[1]); Vector3 up(p_transform[1]);
Vector3 localc(p_param2[2]); Vector3 dir(p_transform[2]);
Vector3 local30(p_param2[3]); Vector3 pos(p_transform[3]);
Mx3DPointFloat local28; Mx3DPointFloat sndCoeff;
local28 = m_eq[1]; sndCoeff = m_coefficients[1];
local28 *= p_param1; sndCoeff *= p_curveParameter;
local30 = m_eq[0]; pos = m_coefficients[0];
local30 *= local34; pos *= curveParameterSquare;
local30 += local28; pos += sndCoeff;
local30 += m_eq[2]; pos += m_coefficients[2];
localc = m_eq[0]; dir = m_coefficients[0];
localc *= 2.0f; dir *= 2.0f;
localc *= p_param1; dir *= p_curveParameter;
localc += m_eq[1]; dir += m_coefficients[1];
localc *= -1.0f; dir *= -1.0f;
if (localc.Unitize() != 0) { if (dir.Unitize() != 0) {
assert(0); assert(0);
return FAILURE; return FAILURE;
} }
local14[1] = local14[2] = 0.0f; right[1] = right[2] = 0.0f;
local14[0] = 1.0f; right[0] = 1.0f;
local3c.EqualsCross(localc, local14); up.EqualsCross(dir, right);
if (local3c.Unitize() != 0) { if (up.Unitize() != 0) {
local14[0] = local14[1] = 0.0f; right[0] = right[1] = 0.0f;
local14[2] = 1.0f; right[2] = 1.0f;
local3c.EqualsCross(localc, local14); up.EqualsCross(dir, right);
if (local3c.Unitize() != 0) { if (up.Unitize() != 0) {
assert(0); assert(0);
return FAILURE; return FAILURE;
} }
} }
local14.EqualsCross(local3c, localc); right.EqualsCross(up, dir);
return SUCCESS; return SUCCESS;
} }
@ -254,19 +255,19 @@ void Act3Ammo::Animate(float p_time)
switch (m_actorState & c_maxState) { switch (m_actorState & c_maxState) {
case c_initial: case c_initial:
case c_one: case c_ready:
break; break;
case c_two: case c_hit:
m_unk0x158 = p_time + 2000.0f; m_rotateTimeout = p_time + 2000.0f;
m_actorState = c_three; m_actorState = c_hitAnimation;
return; return;
case c_three: case c_hitAnimation:
MxMatrix transform; MxMatrix transform;
Vector3 positionRef(transform[3]); Vector3 positionRef(transform[3]);
transform = m_roi->GetLocal2World(); transform = m_roi->GetLocal2World();
if (m_unk0x158 > p_time) { if (m_rotateTimeout > p_time) {
Mx3DPointFloat position; Mx3DPointFloat position;
position = positionRef; position = positionRef;
@ -279,9 +280,9 @@ void Act3Ammo::Animate(float p_time)
} }
else { else {
m_actorState = c_initial; m_actorState = c_initial;
m_unk0x158 = 0; m_rotateTimeout = 0;
positionRef -= g_unk0x10104f08; positionRef -= g_hitTranslation;
m_roi->SetLocal2World(transform); m_roi->SetLocal2World(transform);
m_roi->WrappedUpdateWorldData(); m_roi->WrappedUpdateWorldData();
return; return;
@ -292,90 +293,90 @@ void Act3Ammo::Animate(float p_time)
return; return;
} }
if (m_lastTime < 0.0f) { if (m_transformTime < 0.0f) {
m_lastTime = p_time; m_transformTime = p_time;
m_unk0x7c = 0.0f; m_traveledDistance = 0.0f;
} }
MxMatrix local104; MxMatrix transform;
MxMatrix local60; MxMatrix additionalTransform;
float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; float f = (m_BADuration - m_traveledDistance) / m_worldSpeed + m_transformTime;
undefined4 localb4 = 0; undefined4 unused1 = 0;
undefined4 localbc = 0; undefined4 unused2 = 0;
MxU32 local14 = FALSE; MxU32 annihilated = FALSE;
MxU32 localb8 = FALSE; MxU32 reachedTarget = FALSE;
if (f > p_time) { if (f > p_time) {
m_actorTime = (p_time - m_lastTime) * m_worldSpeed + m_actorTime; m_actorTime = (p_time - m_transformTime) * m_worldSpeed + m_actorTime;
m_unk0x7c = (p_time - m_lastTime) * m_worldSpeed + m_unk0x7c; m_traveledDistance = (p_time - m_transformTime) * m_worldSpeed + m_traveledDistance;
m_lastTime = p_time; m_transformTime = p_time;
} }
else { else {
localb8 = TRUE; reachedTarget = TRUE;
m_unk0x7c = m_BADuration; m_traveledDistance = m_BADuration;
m_lastTime = p_time; m_transformTime = p_time;
} }
local104.SetIdentity(); transform.SetIdentity();
MxResult r = FUN_10053db0((m_unk0x7c / m_BADuration) * m_unk0x19c, local104); MxResult r = CalculateTransformOnCurve((m_traveledDistance / m_BADuration) * m_apexParameter, transform);
assert(r == 0); // SUCCESS assert(r == 0); // SUCCESS
local60.SetIdentity(); additionalTransform.SetIdentity();
if (IsPizza()) { if (IsPizza()) {
local60.Scale(2.0f, 2.0f, 2.0f); additionalTransform.Scale(2.0f, 2.0f, 2.0f);
} }
else { else {
local60.Scale(5.0f, 5.0f, 5.0f); additionalTransform.Scale(5.0f, 5.0f, 5.0f);
} }
if (localb8) { if (reachedTarget) {
if (m_boundary != NULL) { if (m_boundary != NULL) {
Vector3 local17c(local104[0]); Vector3 right(transform[0]);
Vector3 local184(local104[1]); Vector3 up(transform[1]);
Vector3 local174(local104[2]); Vector3 dir(transform[2]);
if (IsPizza()) { if (IsPizza()) {
local184 = *m_boundary->GetUp(); up = *m_boundary->GetUp();
local17c[0] = 1.0f; right[0] = 1.0f;
local17c[1] = local17c[2] = 0.0f; right[1] = right[2] = 0.0f;
local174.EqualsCross(local17c, local184); dir.EqualsCross(right, up);
local174.Unitize(); dir.Unitize();
local17c.EqualsCross(local184, local174); right.EqualsCross(up, dir);
} }
else { else {
local17c = *m_boundary->GetUp(); right = *m_boundary->GetUp();
local184[0] = 1.0f; up[0] = 1.0f;
local184[1] = local184[2] = 0.0f; up[1] = up[2] = 0.0f;
local174.EqualsCross(local17c, local184); dir.EqualsCross(right, up);
local174.Unitize(); dir.Unitize();
local184.EqualsCross(local174, local17c); up.EqualsCross(dir, right);
} }
} }
m_actorState = c_initial; m_actorState = c_initial;
} }
else { else {
local60.RotateX(m_actorTime / 10.0f); additionalTransform.RotateX(m_actorTime / 10.0f);
local60.RotateY(m_actorTime / 6.0f); additionalTransform.RotateY(m_actorTime / 6.0f);
} }
MxMatrix localb0(local104); MxMatrix transformCopy(transform);
local104.Product(local60, localb0); transform.Product(additionalTransform, transformCopy);
m_roi->SetLocal2World(local104); m_roi->SetLocal2World(transform);
m_roi->WrappedUpdateWorldData(); m_roi->WrappedUpdateWorldData();
if (m_BADuration <= m_unk0x7c) { if (m_BADuration <= m_traveledDistance) {
m_worldSpeed = 0.0f; m_worldSpeed = 0.0f;
} }
Vector3 local68(local104[3]); Vector3 position(transform[3]);
if (localb8) { if (reachedTarget) {
if (IsBit4()) { if (IsShootWithoutBoundary()) {
if (IsPizza()) { if (IsPizza()) {
m_world->RemovePizza(*this); m_world->RemovePizza(*this);
m_world->TriggerHitSound(2); m_world->TriggerHitSound(2);
@ -414,16 +415,16 @@ void Act3Ammo::Animate(float p_time)
assert(r); assert(r);
if (!strncmp(r->GetName(), "pammo", 5)) { if (!strncmp(r->GetName(), "pammo", 5)) {
Mx3DPointFloat local1c8; Mx3DPointFloat otherPosition;
Mx3DPointFloat local1b4; Mx3DPointFloat distance;
local1c8 = r->GetLocal2World()[3]; otherPosition = r->GetLocal2World()[3];
local1b4 = m_roi->GetLocal2World()[3]; distance = m_roi->GetLocal2World()[3];
local1b4 -= local1c8; distance -= otherPosition;
float radius = r->GetWorldBoundingSphere().Radius(); float radius = r->GetWorldBoundingSphere().Radius();
if (local1b4.LenSquared() <= radius * radius) { if (distance.LenSquared() <= radius * radius) {
MxS32 index = -1; MxS32 index = -1;
if (sscanf(r->GetName(), "pammo%d", &index) != 1) { if (sscanf(r->GetName(), "pammo%d", &index) != 1) {
assert(0); assert(0);
@ -444,22 +445,22 @@ void Act3Ammo::Animate(float p_time)
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE); SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE);
m_world->RemoveDonut(*this); m_world->RemoveDonut(*this);
local14 = TRUE; annihilated = TRUE;
break; break;
} }
} }
} }
else if (!strncmp(r->GetName(), "dammo", 5)) { else if (!strncmp(r->GetName(), "dammo", 5)) {
Mx3DPointFloat local1f8; Mx3DPointFloat otherPosition;
Mx3DPointFloat local1e4; Mx3DPointFloat distance;
local1f8 = r->GetLocal2World()[3]; otherPosition = r->GetLocal2World()[3];
local1e4 = m_roi->GetLocal2World()[3]; distance = m_roi->GetLocal2World()[3];
local1e4 -= local1f8; distance -= otherPosition;
float radius = r->GetWorldBoundingSphere().Radius(); float radius = r->GetWorldBoundingSphere().Radius();
if (local1e4.LenSquared() <= radius * radius) { if (distance.LenSquared() <= radius * radius) {
MxS32 index = -1; MxS32 index = -1;
if (sscanf(r->GetName(), "dammo%d", &index) != 1) { if (sscanf(r->GetName(), "dammo%d", &index) != 1) {
assert(0); assert(0);
@ -473,19 +474,19 @@ void Act3Ammo::Animate(float p_time)
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE); SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE);
m_world->RemovePizza(*this); m_world->RemovePizza(*this);
local14 = TRUE; annihilated = TRUE;
break; break;
} }
} }
} }
} }
if (!local14) { if (!annihilated) {
if (IsPizza()) { if (IsPizza()) {
m_world->FUN_10073360(*this, local68); m_world->FUN_10073360(*this, position);
} }
else { else {
m_world->FUN_10073390(*this, local68); m_world->FUN_10073390(*this, position);
} }
m_worldSpeed = -1.0f; m_worldSpeed = -1.0f;

View File

@ -19,8 +19,8 @@ DECOMP_SIZE_ASSERT(Bike, 0x164)
Bike::Bike() Bike::Bike()
{ {
m_maxLinearVel = 20.0; m_maxLinearVel = 20.0;
m_unk0x150 = 3.0; m_linearRotationRatio = 3.0;
m_unk0x148 = 1; m_canRotate = 1;
} }
// FUNCTION: LEGO1 0x100768f0 // FUNCTION: LEGO1 0x100768f0

View File

@ -13,15 +13,15 @@ DECOMP_SIZE_ASSERT(Doors, 0x1f8)
// GLOBAL: LEGO1 0x100d8e7c // GLOBAL: LEGO1 0x100d8e7c
// GLOBAL: BETA10 0x101b954c // GLOBAL: BETA10 0x101b954c
MxFloat g_unk0x100d8e7c = 1000.0f; MxFloat g_timeMoving = 1000.0f;
// GLOBAL: LEGO1 0x100d8e80 // GLOBAL: LEGO1 0x100d8e80
// GLOBAL: BETA10 0x101b9550 // GLOBAL: BETA10 0x101b9550
MxFloat g_unk0x100d8e80 = 4000.0f; MxFloat g_timeOpened = 4000.0f;
// GLOBAL: LEGO1 0x100d8e84 // GLOBAL: LEGO1 0x100d8e84
// GLOBAL: BETA10 0x101b9554 // GLOBAL: BETA10 0x101b9554
MxFloat g_unk0x100d8e84 = 6000.0f; MxFloat g_totalTime = 6000.0f; // = g_timeMoving + g_totalTime + g_timeMoving
// FUNCTION: LEGO1 0x10066100 // FUNCTION: LEGO1 0x10066100
// FUNCTION: BETA10 0x10026850 // FUNCTION: BETA10 0x10026850
@ -29,36 +29,36 @@ MxResult Doors::HitActor(LegoPathActor* p_actor, MxBool p_bool)
{ {
assert(m_ltDoor && m_rtDoor); assert(m_ltDoor && m_rtDoor);
if (m_unk0x154 == 1) { if (m_state == e_closed) {
m_unk0x154 = 2; m_state = e_cycling;
m_unk0x158 = Timer()->GetTime(); m_hitTime = Timer()->GetTime();
m_ltDoorLocal = m_ltDoor->GetLocal2World(); m_ltDoorOriginalLocal = m_ltDoor->GetLocal2World();
m_rtDoorLocal = m_rtDoor->GetLocal2World(); m_rtDoorOriginalLocal = m_rtDoor->GetLocal2World();
} }
return m_unk0x1f4 < 0.001 ? SUCCESS : FAILURE; return m_angle < 0.001 ? SUCCESS : FAILURE;
} }
// FUNCTION: LEGO1 0x10066190 // FUNCTION: LEGO1 0x10066190
// FUNCTION: BETA10 0x1002696b // FUNCTION: BETA10 0x1002696b
MxFloat Doors::VTable0xcc(float p_time) MxFloat Doors::CalculateAngle(float p_time)
{ {
MxFloat fVar1; MxFloat timeSinceHit;
fVar1 = p_time - m_unk0x158; timeSinceHit = p_time - m_hitTime;
if (fVar1 <= 0.0f) { if (timeSinceHit <= 0.0f) {
return 0.0f; return 0.0f;
} }
if (fVar1 <= g_unk0x100d8e7c) { if (timeSinceHit <= g_timeMoving) {
return fVar1 * 1.570796 / g_unk0x100d8e7c; return timeSinceHit * 1.570796 / g_timeMoving;
} }
else if (fVar1 <= g_unk0x100d8e7c + g_unk0x100d8e80) { else if (timeSinceHit <= g_timeMoving + g_timeOpened) {
return 1.570796012878418; // Pi / 2 return 1.570796012878418; // Pi / 2
} }
else if (fVar1 <= g_unk0x100d8e84) { else if (timeSinceHit <= g_totalTime) {
return (1.0 - ((fVar1 - g_unk0x100d8e80) - g_unk0x100d8e7c) / g_unk0x100d8e7c) * 1.570796; return (1.0 - ((timeSinceHit - g_timeOpened) - g_timeMoving) / g_timeMoving) * 1.570796;
} }
return 0.0f; return 0.0f;
@ -71,46 +71,46 @@ void Doors::Animate(float p_time)
assert(m_ltDoor && m_rtDoor); assert(m_ltDoor && m_rtDoor);
// TODO: Match // TODO: Match
m_roi->SetVisibility(m_boundary->GetFlag0x10()); m_roi->SetVisibility(m_boundary->GetVisibility());
switch (m_unk0x154) { switch (m_state) {
case 0: case e_none:
m_unk0x154 = 1; m_state = e_closed;
m_actorState = c_initial; m_actorState = c_initial;
break; break;
case 1: case e_closed:
break; break;
case 2: case e_cycling:
float local8 = VTable0xcc(p_time); float angle = CalculateAngle(p_time);
if (local8 > 0.0f) { if (angle > 0.0f) {
MxMatrix local58(m_ltDoorLocal); MxMatrix transform(m_ltDoorOriginalLocal);
Vector3 local10(local58[3]); Vector3 position(transform[3]);
local10.Clear(); position.Clear();
local58.RotateY(-local8); transform.RotateY(-angle);
local10 = m_ltDoorLocal[3]; position = m_ltDoorOriginalLocal[3];
m_ltDoor->SetLocal2World(local58); m_ltDoor->SetLocal2World(transform);
m_ltDoor->WrappedUpdateWorldData(); m_ltDoor->WrappedUpdateWorldData();
local58 = m_rtDoorLocal; transform = m_rtDoorOriginalLocal;
local10.Clear(); position.Clear();
local58.RotateY(local8); transform.RotateY(angle);
local10 = m_rtDoorLocal[3]; position = m_rtDoorOriginalLocal[3];
m_rtDoor->SetLocal2World(local58); m_rtDoor->SetLocal2World(transform);
m_rtDoor->WrappedUpdateWorldData(); m_rtDoor->WrappedUpdateWorldData();
m_unk0x1f4 = local8; m_angle = angle;
} }
if (m_unk0x158 + g_unk0x100d8e84 < p_time) { if (m_hitTime + g_totalTime < p_time) {
m_ltDoor->SetLocal2World(m_ltDoorLocal); m_ltDoor->SetLocal2World(m_ltDoorOriginalLocal);
m_rtDoor->SetLocal2World(m_rtDoorLocal); m_rtDoor->SetLocal2World(m_rtDoorOriginalLocal);
m_ltDoor->WrappedUpdateWorldData(); m_ltDoor->WrappedUpdateWorldData();
m_rtDoor->WrappedUpdateWorldData(); m_rtDoor->WrappedUpdateWorldData();
m_unk0x154 = 1; m_state = e_closed;
m_actorState = c_initial; m_actorState = c_initial;
m_unk0x1f4 = 0; m_angle = 0;
} }
} }
} }

View File

@ -384,7 +384,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param)
} }
// FUNCTION: LEGO1 0x10003e90 // FUNCTION: LEGO1 0x10003e90
void Helicopter::VTable0x74(Matrix4& p_transform) void Helicopter::ApplyTransform(Matrix4& p_transform)
{ {
if (m_userNavFlag) { if (m_userNavFlag) {
m_roi->UpdateTransformationRelativeToParent(p_transform); m_roi->UpdateTransformationRelativeToParent(p_transform);

View File

@ -92,7 +92,7 @@ void IslePathActor::Enter()
NavController()->ResetMaxLinearVel(m_maxLinearVel); NavController()->ResetMaxLinearVel(m_maxLinearVel);
SetUserActor(this); SetUserActor(this);
FUN_1001b660(); TurnAround();
TransformPointOfView(); TransformPointOfView();
} }
} }
@ -151,7 +151,7 @@ void IslePathActor::Exit()
GameState()->m_currentArea = LegoGameState::Area::e_vehicleExited; GameState()->m_currentArea = LegoGameState::Area::e_vehicleExited;
} }
FUN_1001b660(); TurnAround();
TransformPointOfView(); TransformPointOfView();
ResetViewVelocity(); ResetViewVelocity();
} }
@ -611,7 +611,7 @@ void IslePathActor::SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8
} }
// FUNCTION: LEGO1 0x1001b5b0 // FUNCTION: LEGO1 0x1001b5b0
void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset) void IslePathActor::UpdateWorld(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset)
{ {
if (m_world) { if (m_world) {
m_world->RemoveActor(this); m_world->RemoveActor(this);
@ -639,15 +639,15 @@ void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundar
// FUNCTION: LEGO1 0x1001b660 // FUNCTION: LEGO1 0x1001b660
// FUNCTION: BETA10 0x10036ea2 // FUNCTION: BETA10 0x10036ea2
void IslePathActor::FUN_1001b660() void IslePathActor::TurnAround()
{ {
MxMatrix transform(m_roi->GetLocal2World()); MxMatrix transform(m_roi->GetLocal2World());
Vector3 position(transform[0]); Vector3 right(transform[0]);
Vector3 direction(transform[1]); Vector3 up(transform[1]);
Vector3 up(transform[2]); Vector3 direction(transform[2]);
up *= -1.0f; direction *= -1.0f;
position.EqualsCross(direction, up); right.EqualsCross(up, direction);
m_roi->SetLocal2World(transform); m_roi->SetLocal2World(transform);
m_roi->WrappedUpdateWorldData(); m_roi->WrappedUpdateWorldData();
} }

View File

@ -35,8 +35,8 @@ const char* g_varJSWNSHY5 = "c_jswnshy5";
Jetski::Jetski() Jetski::Jetski()
{ {
m_maxLinearVel = 25.0; m_maxLinearVel = 25.0;
m_unk0x150 = 2.0; m_linearRotationRatio = 2.0;
m_unk0x148 = 1; m_canRotate = 1;
} }
// FUNCTION: LEGO1 0x1007e630 // FUNCTION: LEGO1 0x1007e630

View File

@ -24,8 +24,8 @@ DECOMP_SIZE_ASSERT(Motocycle, 0x16c)
Motocycle::Motocycle() Motocycle::Motocycle()
{ {
m_maxLinearVel = 40.0; m_maxLinearVel = 40.0;
m_unk0x150 = 1.75; m_linearRotationRatio = 1.75;
m_unk0x148 = 1; m_canRotate = 1;
m_fuel = 1.0; m_fuel = 1.0;
} }

View File

@ -22,8 +22,8 @@ SkateBoard::SkateBoard()
{ {
m_pizzaVisible = FALSE; m_pizzaVisible = FALSE;
m_maxLinearVel = 15.0; m_maxLinearVel = 15.0;
m_unk0x150 = 3.5; m_linearRotationRatio = 3.5;
m_unk0x148 = 1; m_canRotate = 1;
NotificationManager()->Register(this); NotificationManager()->Register(this);
} }

View File

@ -123,7 +123,7 @@ void LegoCarBuildAnimPresenter::PutFrame()
MoveShelfForward(); MoveShelfForward();
case e_stopped: case e_stopped:
if (m_carBuildEntity->GetROI()) { if (m_carBuildEntity->GetROI()) {
FUN_1006b9a0(m_anim, m_shelfFrameBuffer, NULL); ApplyTransformWithVisibilityAndCam(m_anim, m_shelfFrameBuffer, NULL);
} }
default: default:
break; break;
@ -591,7 +591,7 @@ void LegoCarBuildAnimPresenter::RotateAroundYAxis(MxFloat p_angle)
m_platformAnimNodeData->GetRotationKey(0)->SetAngle(newRotation[3]); m_platformAnimNodeData->GetRotationKey(0)->SetAngle(newRotation[3]);
if (m_carBuildEntity->GetROI()) { if (m_carBuildEntity->GetROI()) {
FUN_1006b9a0(&m_platformAnim, m_shelfFrameBuffer, NULL); ApplyTransformWithVisibilityAndCam(&m_platformAnim, m_shelfFrameBuffer, NULL);
} }
} }
} }

View File

@ -26,7 +26,7 @@ void LegoActionControlPresenter::ReadyTickle()
m_subscriber->FreeDataChunk(chunk); m_subscriber->FreeDataChunk(chunk);
if (m_compositePresenter) { if (m_compositePresenter) {
if (m_action->GetDuration() == -1 || m_action->GetFlags() & 1) { if (m_action->GetDuration() == -1 || m_action->GetFlags() & 1) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
} }
} }
@ -36,11 +36,11 @@ void LegoActionControlPresenter::ReadyTickle()
void LegoActionControlPresenter::RepeatingTickle() void LegoActionControlPresenter::RepeatingTickle()
{ {
if (IsEnabled()) { if (IsEnabled()) {
if (m_unk0x50 == 0) { if (m_actionType == 0) {
ParseExtra(); ParseExtra();
} }
InvokeAction(m_unk0x50, MxAtomId(m_unk0x54.GetData(), e_lowerCase2), m_unk0x64, NULL); InvokeAction(m_actionType, MxAtomId(m_sourceName.GetData(), e_lowerCase2), m_streamId, NULL);
ProgressTickleState(e_done); ProgressTickleState(e_done);
} }
} }
@ -84,15 +84,15 @@ void LegoActionControlPresenter::ParseExtra()
char output[1024]; char output[1024];
if (KeyValueStringParse(output, g_strACTION, extraCopy)) { if (KeyValueStringParse(output, g_strACTION, extraCopy)) {
m_unk0x50 = MatchActionString(strtok(output, g_parseExtraTokens)); m_actionType = MatchActionString(strtok(output, g_parseExtraTokens));
if (m_unk0x50 != Extra::ActionType::e_exit) { if (m_actionType != Extra::ActionType::e_exit) {
MakeSourceName(extraCopy, strtok(NULL, g_parseExtraTokens)); MakeSourceName(extraCopy, strtok(NULL, g_parseExtraTokens));
m_unk0x54 = extraCopy; m_sourceName = extraCopy;
m_unk0x54.ToLowerCase(); m_sourceName.ToLowerCase();
if (m_unk0x50 != Extra::ActionType::e_run) { if (m_actionType != Extra::ActionType::e_run) {
m_unk0x64 = atoi(strtok(NULL, g_parseExtraTokens)); m_streamId = atoi(strtok(NULL, g_parseExtraTokens));
} }
} }
} }

View File

@ -315,7 +315,7 @@ MxS32 g_legoAnimationManagerConfig = 1;
float g_unk0x100f7500 = 0.1f; float g_unk0x100f7500 = 0.1f;
// GLOBAL: LEGO1 0x100f7504 // GLOBAL: LEGO1 0x100f7504
MxS32 g_unk0x100f7504 = 0; MxS32 g_pathWalkingModeSelector = 0;
// FUNCTION: LEGO1 0x1005eb50 // FUNCTION: LEGO1 0x1005eb50
void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig) void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig)
@ -1933,10 +1933,10 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und)
} }
if (i != m_numAllowedExtras) { if (i != m_numAllowedExtras) {
MxU8 und = SDL_rand(2) != 0 ? 1 : 2; MxU8 pathWalkingMode = SDL_rand(2) != 0 ? 1 : 2;
MxBool bool1, bool2; MxBool bool1, bool2;
switch (g_unk0x100f7504 % 4) { switch (g_pathWalkingModeSelector % 4) {
case 0: case 0:
bool1 = FALSE; bool1 = FALSE;
bool2 = FALSE; bool2 = FALSE;
@ -1954,7 +1954,7 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und)
if (p_location < 0) { if (p_location < 0) {
boundary = new LegoLocation::Boundary; boundary = new LegoLocation::Boundary;
if (!FUN_10064120(boundary, und == 2, bool2)) { if (!FUN_10064120(boundary, pathWalkingMode == 2, bool2)) {
delete boundary; delete boundary;
boundary = NULL; boundary = NULL;
} }
@ -2008,19 +2008,19 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und)
g_characters[m_lastExtraCharacterId].m_name g_characters[m_lastExtraCharacterId].m_name
); );
switch (g_unk0x100f7504++ % 4) { switch (g_pathWalkingModeSelector++ % 4) {
case 0: case 0:
actor->SetUnknown0x0c(und != 1 ? 1 : 2); actor->SetPathWalkingMode(pathWalkingMode != 1 ? 1 : 2);
break; break;
case 1: { case 1: {
actor->SetUnknown0x0c(und); actor->SetPathWalkingMode(pathWalkingMode);
MxS32 src = boundary->m_src; MxS32 src = boundary->m_src;
boundary->m_src = boundary->m_dest; boundary->m_src = boundary->m_dest;
boundary->m_dest = src; boundary->m_dest = src;
break; break;
} }
default: default:
actor->SetUnknown0x0c(und); actor->SetPathWalkingMode(pathWalkingMode);
break; break;
} }
@ -2190,21 +2190,21 @@ MxBool LegoAnimationManager::FUN_10062e20(LegoROI* p_roi, LegoAnimPresenter* p_p
MxResult result = 1; // Not a valid MxResult value MxResult result = 1; // Not a valid MxResult value
if (!local24) { if (!local24) {
MxU8 unk0x0c; MxU8 pathWalkingMode;
switch (SDL_rand(3)) { switch (SDL_rand(3)) {
case 0: case 0:
unk0x0c = 1; pathWalkingMode = 1;
break; break;
case 1: case 1:
unk0x0c = 2; pathWalkingMode = 2;
break; break;
case 2: case 2:
unk0x0c = 0; pathWalkingMode = 0;
break; break;
} }
actor->SetUnknown0x0c(unk0x0c); actor->SetPathWalkingMode(pathWalkingMode);
Mx3DPointFloat position; Mx3DPointFloat position;
Mx3DPointFloat direction; Mx3DPointFloat direction;
@ -2390,7 +2390,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_
presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(p_actor, 1.7f); presenter->CreateROIAndBuildMap(p_actor, 1.7f);
} }
g_vehicles[g_characters[p_characterId].m_vehicleId].m_unk0x04 = FALSE; g_vehicles[g_characters[p_characterId].m_vehicleId].m_unk0x04 = FALSE;
@ -2403,7 +2403,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_
presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(p_actor, 0.7f); presenter->CreateROIAndBuildMap(p_actor, 0.7f);
} }
} }
@ -2416,7 +2416,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_
presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(p_actor, 4.0f); presenter->CreateROIAndBuildMap(p_actor, 4.0f);
} }
} }
@ -2429,7 +2429,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_
presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(p_actor, 0.0f); presenter->CreateROIAndBuildMap(p_actor, 0.0f);
} }
} }
@ -2701,8 +2701,8 @@ MxResult LegoAnimationManager::FUN_10064380(
} }
if (actor != NULL) { if (actor != NULL) {
MxU8 unk0x0c = SDL_rand(2) != 0 ? 1 : 2; MxU8 pathWalkingMode = SDL_rand(2) != 0 ? 1 : 2;
actor->SetUnknown0x0c(unk0x0c); actor->SetPathWalkingMode(pathWalkingMode);
actor->SetWorldSpeed(0.0f); actor->SetWorldSpeed(0.0f);
if (world->PlaceActor(actor, p_boundaryName, p_src, p_srcScale, p_dest, p_destScale) != SUCCESS) { if (world->PlaceActor(actor, p_boundaryName, p_src, p_srcScale, p_dest, p_destScale) != SUCCESS) {
@ -2718,12 +2718,12 @@ MxResult LegoAnimationManager::FUN_10064380(
LegoLocomotionAnimPresenter* presenter = LegoLocomotionAnimPresenter* presenter =
(LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx1]); (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx1]);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(actor, 0.0f); presenter->CreateROIAndBuildMap(actor, 0.0f);
} }
presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx2]); presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx2]);
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006d680(actor, 4.0f); presenter->CreateROIAndBuildMap(actor, 4.0f);
} }
m_extras[i].m_unk0x08 = Timer()->GetTime(); m_extras[i].m_unk0x08 = Timer()->GetTime();

View File

@ -152,7 +152,7 @@ void LegoAnimMMPresenter::ReadyTickle()
} }
if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) { if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) {
m_presenter->VTable0xa0(*m_tranInfo->m_unk0x0c); m_presenter->SetTransform(*m_tranInfo->m_unk0x0c);
} }
if (m_presenter != NULL) { if (m_presenter != NULL) {
@ -168,7 +168,7 @@ void LegoAnimMMPresenter::StartingTickle()
{ {
if (m_presenter == NULL || m_presenter->GetCurrentTickleState() == e_idle) { if (m_presenter == NULL || m_presenter->GetCurrentTickleState() == e_idle) {
if (m_tranInfo != NULL && m_tranInfo->m_unk0x08 != NULL) { if (m_tranInfo != NULL && m_tranInfo->m_unk0x08 != NULL) {
m_presenter->FUN_1006b140(m_tranInfo->m_unk0x08); m_presenter->CopyTransform(m_tranInfo->m_unk0x08);
} }
m_unk0x50 = Timer()->GetTime(); m_unk0x50 = Timer()->GetTime();
@ -225,7 +225,7 @@ MxLong LegoAnimMMPresenter::Notify(MxParam& p_param)
} }
// FUNCTION: LEGO1 0x1004b360 // FUNCTION: LEGO1 0x1004b360
void LegoAnimMMPresenter::VTable0x60(MxPresenter* p_presenter) void LegoAnimMMPresenter::AdvanceSerialAction(MxPresenter* p_presenter)
{ {
if (m_presenter == p_presenter && ((MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_streaming || if (m_presenter == p_presenter && ((MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_streaming ||
(MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_done)) { (MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_done)) {
@ -316,7 +316,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b450()
MxBool LegoAnimMMPresenter::FUN_1004b530(MxLong p_time) MxBool LegoAnimMMPresenter::FUN_1004b530(MxLong p_time)
{ {
if (m_presenter != NULL) { if (m_presenter != NULL) {
m_presenter->FUN_1006afc0(m_unk0x68, 0); m_presenter->GetTransforms(m_unk0x68, 0);
m_roiMap = m_presenter->GetROIMap(m_roiMapSize); m_roiMap = m_presenter->GetROIMap(m_roiMapSize);
m_roiMapSize++; m_roiMapSize++;
} }
@ -403,7 +403,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b610(MxLong p_time)
m_action->SetTimeStarted(Timer()->GetTime()); m_action->SetTimeStarted(Timer()->GetTime());
if (m_compositePresenter != NULL) { if (m_compositePresenter != NULL) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
return TRUE; return TRUE;
@ -471,10 +471,10 @@ MxBool LegoAnimMMPresenter::FUN_1004b6d0(MxLong p_time)
} }
#ifdef BETA10 #ifdef BETA10
actor->VTable0xa8(); actor->ApplyLocal2World();
#else #else
if (m_tranInfo->m_unk0x29) { if (m_tranInfo->m_unk0x29) {
actor->VTable0xa8(); actor->ApplyLocal2World();
} }
#endif #endif
} }
@ -498,7 +498,7 @@ void LegoAnimMMPresenter::FUN_1004b840()
MxDSAction* action = m_action; MxDSAction* action = m_action;
if (m_presenter != NULL) { if (m_presenter != NULL) {
m_presenter->FUN_1006c7a0(); m_presenter->ApplyFinishedTransform();
} }
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {

View File

@ -0,0 +1,156 @@
#include "legotesttimer.h"
#include "legoeventnotificationparam.h"
#include "legoinputmanager.h"
#include "misc.h"
#include "mxnotificationparam.h"
#include <stdio.h>
// FUNCTION: BETA10 0x100d1030
LegoTestTimer::LegoTestTimer(LegoS32 p_numTimers, LegoS32 p_interval, LegoS32 p_numBins, LegoS32 p_type)
{
m_enable = FALSE;
m_keyRegistered = FALSE;
if (p_interval > 0) {
m_numTimers = p_numTimers;
m_interval = p_interval;
m_numBins = p_numBins / m_interval;
m_lastTime = new LegoS32[m_numTimers];
m_totalTime = new LegoS32[m_numTimers];
m_timers = new LegoS32*[m_numTimers];
for (int i = 0; i < m_numTimers; i++) {
m_lastTime[i] = -1;
m_timers[i] = new LegoS32[m_numBins];
for (int j = 0; j < m_numBins; j++) {
m_timers[i][j] = 0;
}
}
}
else {
m_numTimers = 0;
m_interval = 0;
m_numBins = 0;
m_lastTime = NULL;
m_totalTime = NULL;
m_timers = NULL;
}
}
// FUNCTION: BETA10 0x100d11ee
LegoTestTimer::~LegoTestTimer()
{
if (m_keyRegistered && InputManager()) {
InputManager()->UnRegister(this);
}
m_enable = FALSE;
if (m_numTimers != 0) {
delete[] m_lastTime;
delete[] m_totalTime;
for (int i = 0; i < m_numTimers; i++) {
delete m_timers[i];
}
delete[] m_timers;
}
}
// FUNCTION: BETA10 0x100d132c
void LegoTestTimer::Tick(LegoS32 p_timer)
{
if (m_enable) {
MxULong time = timeGetTime();
LegoS32 prev = p_timer ? p_timer - 1 : 0;
if (m_lastTime[p_timer] == -1) {
m_lastTime[p_timer] = time;
m_totalTime[p_timer] = 0;
for (int i = 0; i < m_numBins; i++) {
m_timers[p_timer][i] = 0;
}
}
else {
LegoS32 dtim = time - m_lastTime[prev];
if (dtim < 0) {
dtim = 0;
}
m_lastTime[p_timer] = time;
LegoS32 binIndex = dtim / m_interval;
if (binIndex >= m_numBins) {
binIndex = m_numBins - 1;
}
m_timers[p_timer][binIndex]++;
m_totalTime[p_timer] += dtim;
}
}
else if (!m_keyRegistered) {
InputManager()->Register(this);
m_keyRegistered = TRUE;
}
}
// FUNCTION: BETA10 0x100d148f
void LegoTestTimer::Print()
{
FILE* f = fopen("\\TEST_TIME.TXT", "w");
if (f) {
int i;
fprintf(f, "timer");
for (i = 0; i < m_numTimers; i++) {
fprintf(f, "%8d ", i);
}
fprintf(f, "\n");
for (int k = 0; k < m_numBins; k++) {
fprintf(f, "%3d: ", m_interval * (k + 1));
for (int j = 0; j < m_numTimers; j++) {
fprintf(f, "%8d ", m_timers[j][k]);
}
fprintf(f, "\n");
}
fprintf(f, "ttime");
for (i = 0; i < m_numTimers; i++) {
fprintf(f, "%8d ", m_totalTime[i]);
}
fclose(f);
}
ResetAtNextTick();
}
// FUNCTION: BETA10 0x100d161e
void LegoTestTimer::ResetAtNextTick()
{
for (int i = 0; i < m_numTimers; i++) {
m_lastTime[i] = -1;
}
}
// FUNCTION: BETA10 0x100d1667
MxLong LegoTestTimer::Notify(MxParam& p_param)
{
if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) {
MxU8 key = ((LegoEventNotificationParam&) p_param).GetKey();
if (key == 's' || key == 'S') {
ResetAtNextTick();
m_enable = TRUE;
}
else if (key == 'p' || key == 'P') {
m_enable = FALSE;
Print();
}
}
return 0;
}

View File

@ -15,8 +15,8 @@ DECOMP_SIZE_ASSERT(MxCompositeMediaPresenter, 0x50)
// FUNCTION: LEGO1 0x10073ea0 // FUNCTION: LEGO1 0x10073ea0
MxCompositeMediaPresenter::MxCompositeMediaPresenter() MxCompositeMediaPresenter::MxCompositeMediaPresenter()
{ {
m_unk0x4c = 0; m_remainingChildren = 0;
m_unk0x4e = FALSE; m_allChildrenStreaming = FALSE;
VideoManager()->RegisterPresenter(*this); VideoManager()->RegisterPresenter(*this);
} }
@ -99,25 +99,25 @@ void MxCompositeMediaPresenter::StartingTickle()
{ {
AUTOLOCK(m_criticalSection); AUTOLOCK(m_criticalSection);
if (!m_unk0x4e) { if (!m_allChildrenStreaming) {
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {
if ((*it)->GetCurrentTickleState() < e_streaming) { if ((*it)->GetCurrentTickleState() < e_streaming) {
(*it)->Tickle(); (*it)->Tickle();
if ((*it)->GetCurrentTickleState() == e_streaming || if ((*it)->GetCurrentTickleState() == e_streaming ||
((*it)->GetAction() && (*it)->GetAction()->GetStartTime())) { ((*it)->GetAction() && (*it)->GetAction()->GetStartTime())) {
m_unk0x4c++; m_remainingChildren++;
} }
} }
} }
if (m_list.size() == m_unk0x4c) { if (m_list.size() == m_remainingChildren) {
m_unk0x4e = TRUE; m_allChildrenStreaming = TRUE;
m_unk0x4c = 0; m_remainingChildren = 0;
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {
if (!(*it)->GetAction()->GetStartTime()) { if (!(*it)->GetAction()->GetStartTime()) {
m_unk0x4c++; m_remainingChildren++;
} }
} }
} }
@ -128,11 +128,11 @@ void MxCompositeMediaPresenter::StartingTickle()
!((*it)->GetAction()->GetFlags() & MxDSAction::c_bit9)) { !((*it)->GetAction()->GetFlags() & MxDSAction::c_bit9)) {
(*it)->Tickle(); (*it)->Tickle();
(*it)->GetAction()->SetFlags((*it)->GetAction()->GetFlags() | MxDSAction::c_bit9); (*it)->GetAction()->SetFlags((*it)->GetAction()->GetFlags() | MxDSAction::c_bit9);
m_unk0x4c--; m_remainingChildren--;
} }
} }
if (!m_unk0x4c) { if (!m_remainingChildren) {
ProgressTickleState(e_streaming); ProgressTickleState(e_streaming);
MxLong time = Timer()->GetTime(); MxLong time = Timer()->GetTime();
m_action->SetTimeStarted(time); m_action->SetTimeStarted(time);

View File

@ -142,11 +142,11 @@ LegoNavController::LegoNavController()
m_linearAccel = 0.0f; m_linearAccel = 0.0f;
m_rotationalAccel = 0.0f; m_rotationalAccel = 0.0f;
m_trackDefault = FALSE; m_trackDefault = FALSE;
m_unk0x5d = FALSE; m_keyPressed = FALSE;
m_isAccelerating = FALSE; m_isAccelerating = FALSE;
m_unk0x64 = 0.0f; m_additionalScale = 0.0f;
m_unk0x68 = 0.0f; m_additionalRotationY = 0.0f;
m_unk0x60 = 0.0f; m_additionalHeightOffset = 0.0f;
m_lastTime = Timer()->GetTime(); m_lastTime = Timer()->GetTime();
@ -330,7 +330,7 @@ MxBool LegoNavController::CalculateNewPosDir(
const Vector3& p_curDir, const Vector3& p_curDir,
Vector3& p_newPos, Vector3& p_newPos,
Vector3& p_newDir, Vector3& p_newDir,
const Vector3* p_und const Vector3* p_up
) )
{ {
if (!g_isWorldActive) { if (!g_isWorldActive) {
@ -338,14 +338,14 @@ MxBool LegoNavController::CalculateNewPosDir(
} }
MxBool changed = FALSE; MxBool changed = FALSE;
MxBool und = FALSE; MxBool rotatedY = FALSE;
MxTime currentTime = Timer()->GetTime(); MxTime currentTime = Timer()->GetTime();
float deltaTime = Min((currentTime - m_lastTime) / 1000.0, 1. / 10.); float deltaTime = Min((currentTime - m_lastTime) / 1000.0, 1. / 10.);
m_lastTime = currentTime; m_lastTime = currentTime;
if (ProcessKeyboardInput() == FAILURE) { if (ProcessKeyboardInput() == FAILURE) {
ProcessJoystickInput(und); ProcessJoystickInput(rotatedY);
} }
if (m_useRotationalVel) { if (m_useRotationalVel) {
@ -357,7 +357,7 @@ MxBool LegoNavController::CalculateNewPosDir(
m_linearVel = CalculateNewVel(m_targetLinearVel, m_linearVel, m_linearAccel, deltaTime); m_linearVel = CalculateNewVel(m_targetLinearVel, m_linearVel, m_linearAccel, deltaTime);
if (und || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) { if (rotatedY || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) {
float rot_mat[3][3]; float rot_mat[3][3];
Mx3DPointFloat delta_pos, new_dir, new_pos; Mx3DPointFloat delta_pos, new_dir, new_pos;
@ -376,7 +376,7 @@ MxBool LegoNavController::CalculateNewPosDir(
delta_rad = DTOR(m_rotationalVel * m_rotSensitivity); delta_rad = DTOR(m_rotationalVel * m_rotSensitivity);
} }
if (p_und != NULL && (*p_und)[1] < 0.0f) { if (p_up != NULL && (*p_up)[1] < 0.0f) {
delta_rad = -delta_rad; delta_rad = -delta_rad;
} }
@ -389,7 +389,7 @@ MxBool LegoNavController::CalculateNewPosDir(
changed = TRUE; changed = TRUE;
} }
if (m_unk0x5d) { if (m_keyPressed) {
float rot_mat[3][3]; float rot_mat[3][3];
Mx3DPointFloat delta_pos, new_pos, new_dir; Mx3DPointFloat delta_pos, new_pos, new_dir;
@ -402,20 +402,20 @@ MxBool LegoNavController::CalculateNewPosDir(
SET3(new_dir, p_curDir); SET3(new_dir, p_curDir);
} }
if (m_unk0x64 != 0.0f) { if (m_additionalScale != 0.0f) {
delta_pos[0] = new_dir[0] * m_unk0x64; delta_pos[0] = new_dir[0] * m_additionalScale;
delta_pos[1] = new_dir[1] * m_unk0x64; delta_pos[1] = new_dir[1] * m_additionalScale;
delta_pos[2] = new_dir[2] * m_unk0x64; delta_pos[2] = new_dir[2] * m_additionalScale;
} }
else { else {
FILLVEC3(delta_pos, 0.0f); FILLVEC3(delta_pos, 0.0f);
} }
delta_pos[1] += m_unk0x60; delta_pos[1] += m_additionalHeightOffset;
VPV3(p_newPos, new_pos, delta_pos); VPV3(p_newPos, new_pos, delta_pos);
if (m_unk0x68 != 0.0f) { if (m_additionalRotationY != 0.0f) {
float delta_rad = DTOR(m_unk0x68); float delta_rad = DTOR(m_additionalRotationY);
IDENTMAT3(rot_mat); IDENTMAT3(rot_mat);
rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad); rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad);
rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad); rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad);
@ -426,8 +426,8 @@ MxBool LegoNavController::CalculateNewPosDir(
SET3(p_newDir, new_dir); SET3(p_newDir, new_dir);
} }
m_unk0x60 = m_unk0x64 = m_unk0x68 = 0.0f; m_additionalHeightOffset = m_additionalScale = m_additionalRotationY = 0.0f;
m_unk0x5d = FALSE; m_keyPressed = FALSE;
changed = TRUE; changed = TRUE;
} }
@ -523,7 +523,7 @@ MxS32 LegoNavController::GetNumLocations()
} }
// FUNCTION: LEGO1 0x10055750 // FUNCTION: LEGO1 0x10055750
MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und) MxResult LegoNavController::ProcessJoystickInput(MxBool& p_rotatedY)
{ {
LegoOmni* instance = LegoOmni::GetInstance(); LegoOmni* instance = LegoOmni::GetInstance();
@ -556,7 +556,7 @@ MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und)
if (world && world->GetCameraController()) { if (world && world->GetCameraController()) {
world->GetCameraController()->RotateY(DTOR(povPosition)); world->GetCameraController()->RotateY(DTOR(povPosition));
p_und = TRUE; p_rotatedY = TRUE;
} }
} }
@ -654,7 +654,7 @@ MxResult LegoNavController::ProcessKeyboardInput()
MxLong LegoNavController::Notify(MxParam& p_param) MxLong LegoNavController::Notify(MxParam& p_param)
{ {
if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) { if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) {
m_unk0x5d = TRUE; m_keyPressed = TRUE;
SDL_Keycode originKey = ((LegoEventNotificationParam&) p_param).GetKey(); SDL_Keycode originKey = ((LegoEventNotificationParam&) p_param).GetKey();
SDL_Keycode key = originKey; SDL_Keycode key = originKey;
@ -810,7 +810,7 @@ MxLong LegoNavController::Notify(MxParam& p_param)
g_fpsEnabled = TRUE; g_fpsEnabled = TRUE;
} }
default: default:
m_unk0x5d = FALSE; m_keyPressed = FALSE;
break; break;
case SDLK_0: case SDLK_0:
case SDLK_1: case SDLK_1:
@ -978,7 +978,7 @@ MxLong LegoNavController::Notify(MxParam& p_param)
g_locationCalcStep = 1; g_locationCalcStep = 1;
break; break;
case SDLK_D: case SDLK_D:
m_unk0x60 = -1.0; m_additionalHeightOffset = -1.0;
break; break;
case SDLK_F: case SDLK_F:
RealtimeView::SetUserMaxLOD(0.0); RealtimeView::SetUserMaxLOD(0.0);
@ -1044,7 +1044,7 @@ MxLong LegoNavController::Notify(MxParam& p_param)
BackgroundAudioManager()->Enable(g_enableMusic); BackgroundAudioManager()->Enable(g_enableMusic);
break; break;
case SDLK_U: case SDLK_U:
m_unk0x60 = 1.0; m_additionalHeightOffset = 1.0;
break; break;
case SDLK_V: case SDLK_V:
if (g_nextAnimation > 0 && g_animationCalcStep == 0) { if (g_nextAnimation > 0 && g_animationCalcStep == 0) {

View File

@ -122,8 +122,8 @@ void LegoWorld::Destroy(MxBool p_fromDestructor)
if (presenter->IsA("LegoLocomotionAnimPresenter")) { if (presenter->IsA("LegoLocomotionAnimPresenter")) {
LegoLocomotionAnimPresenter* animPresenter = (LegoLocomotionAnimPresenter*) presenter; LegoLocomotionAnimPresenter* animPresenter = (LegoLocomotionAnimPresenter*) presenter;
animPresenter->DecrementUnknown0xd4(); animPresenter->DecrementWorldRefCounter();
if (animPresenter->GetUnknown0xd4() == 0) { if (animPresenter->GetWorldRefCounter() == 0) {
ApplyMask(action, MxDSAction::c_world, FALSE); ApplyMask(action, MxDSAction::c_world, FALSE);
presenter->EndAction(); presenter->EndAction();
} }
@ -363,7 +363,7 @@ void LegoWorld::AddPresenterIfInRange(LegoAnimPresenter* p_presenter)
LegoPathController* controller; LegoPathController* controller;
while (cursor.Next(controller)) { while (cursor.Next(controller)) {
controller->FUN_100468f0(p_presenter); controller->AddPresenterIfInRange(p_presenter);
} }
} }
@ -382,7 +382,7 @@ void LegoWorld::RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter)
// FUNCTION: LEGO1 0x1001ff80 // FUNCTION: LEGO1 0x1001ff80
void LegoWorld::AddPath(LegoPathController* p_controller) void LegoWorld::AddPath(LegoPathController* p_controller)
{ {
p_controller->FUN_10046bb0(this); p_controller->SetWorld(this);
m_pathControllerList.Append(p_controller); m_pathControllerList.Append(p_controller);
} }
@ -416,7 +416,7 @@ MxResult LegoWorld::GetCurrPathInfo(LegoPathBoundary** p_boundaries, MxS32& p_nu
return FAILURE; return FAILURE;
} }
return controller->FUN_10046b30(*p_boundaries, p_numL); return controller->GetBoundaries(*p_boundaries, p_numL);
} }
// FUNCTION: LEGO1 0x10020220 // FUNCTION: LEGO1 0x10020220

View File

@ -404,9 +404,9 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, SDL_IOStream*
} }
// FUNCTION: LEGO1 0x10067a70 // FUNCTION: LEGO1 0x10067a70
void LegoWorldPresenter::VTable0x60(MxPresenter* p_presenter) void LegoWorldPresenter::AdvanceSerialAction(MxPresenter* p_presenter)
{ {
MxCompositePresenter::VTable0x60(p_presenter); MxCompositePresenter::AdvanceSerialAction(p_presenter);
MxDSAction* action = p_presenter->GetAction(); MxDSAction* action = p_presenter->GetAction();
if (action->GetDuration() != -1 && (action->GetFlags() & MxDSAction::c_looping) == 0) { if (action->GetDuration() != -1 && (action->GetFlags() & MxDSAction::c_looping) == 0) {

View File

@ -63,10 +63,10 @@ MxResult LegoAnimActor::GetTimeInCycle(float& p_timeInCycle)
} }
// FUNCTION: LEGO1 0x1001c240 // FUNCTION: LEGO1 0x1001c240
void LegoAnimActor::VTable0x74(Matrix4& p_transform) void LegoAnimActor::ApplyTransform(Matrix4& p_transform)
{ {
float timeInCycle; float timeInCycle;
LegoPathActor::VTable0x74(p_transform); LegoPathActor::ApplyTransform(p_transform);
if (m_curAnim >= 0) { if (m_curAnim >= 0) {
GetTimeInCycle(timeInCycle); GetTimeInCycle(timeInCycle);
@ -80,19 +80,19 @@ void LegoAnimActor::Animate(float p_time)
{ {
assert(m_roi); assert(m_roi);
if (m_lastTime == 0) { if (m_transformTime == 0) {
m_lastTime = p_time - 1.0f; m_transformTime = p_time - 1.0f;
} }
if (m_actorState == c_initial && !m_userNavFlag && m_worldSpeed <= 0) { if (m_actorState == c_initial && !m_userNavFlag && m_worldSpeed <= 0) {
if (m_curAnim >= 0) { if (m_curAnim >= 0) {
MxMatrix transform(m_unk0xec); MxMatrix transform(m_local2World);
float timeInCycle; float timeInCycle;
GetTimeInCycle(timeInCycle); GetTimeInCycle(timeInCycle);
AnimateWithTransform(timeInCycle, transform); AnimateWithTransform(timeInCycle, transform);
} }
m_lastTime = m_actorTime = p_time; m_transformTime = m_actorTime = p_time;
} }
else { else {
LegoPathActor::Animate(p_time); LegoPathActor::Animate(p_time);
@ -109,7 +109,7 @@ MxResult LegoAnimActor::AnimateWithTransform(float p_time, Matrix4& p_transform)
LegoROI** roiMap = m_animMaps[m_curAnim]->m_roiMap; LegoROI** roiMap = m_animMaps[m_curAnim]->m_roiMap;
MxU32 numROIs = m_animMaps[m_curAnim]->m_numROIs; MxU32 numROIs = m_animMaps[m_curAnim]->m_numROIs;
if (!m_boundary->GetFlag0x10()) { if (!m_boundary->GetVisibility()) {
MxU32 i; MxU32 i;
m_roi->SetVisibility(FALSE); m_roi->SetVisibility(FALSE);
@ -244,7 +244,7 @@ void LegoAnimActor::ParseAction(char* p_extra)
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token) { if (token) {
p->FUN_1006d680(this, atof(token)); p->CreateROIAndBuildMap(this, atof(token));
} }
} }

View File

@ -12,7 +12,7 @@
DECOMP_SIZE_ASSERT(LegoExtraActor, 0x1dc) DECOMP_SIZE_ASSERT(LegoExtraActor, 0x1dc)
// GLOBAL: LEGO1 0x100f31d0 // GLOBAL: LEGO1 0x100f31d0
LegoWorld* g_unk0x100f31d0 = NULL; LegoWorld* g_reassemblyAnimWorld = NULL;
// GLOBAL: LEGO1 0x100f31d4 // GLOBAL: LEGO1 0x100f31d4
LegoLocomotionAnimPresenter* m_assAnimP = NULL; LegoLocomotionAnimPresenter* m_assAnimP = NULL;
@ -21,7 +21,7 @@ LegoLocomotionAnimPresenter* m_assAnimP = NULL;
LegoLocomotionAnimPresenter* m_disAnimP = NULL; LegoLocomotionAnimPresenter* m_disAnimP = NULL;
// GLOBAL: LEGO1 0x100f31dc // GLOBAL: LEGO1 0x100f31dc
MxS32 g_unk0x100f31dc = 0; MxS32 g_hitCounter = 0;
// GLOBAL: LEGO1 0x10104c18 // GLOBAL: LEGO1 0x10104c18
Mx3DPointFloat g_unk0x10104c18 = Mx3DPointFloat(0.0f, 2.5f, 0.0f); Mx3DPointFloat g_unk0x10104c18 = Mx3DPointFloat(0.0f, 2.5f, 0.0f);
@ -32,12 +32,12 @@ LegoExtraActor::LegoExtraActor()
{ {
m_lastPathStruct = 0.0f; m_lastPathStruct = 0.0f;
m_scheduledTime = 0; m_scheduledTime = 0;
m_unk0x0c = 0; m_pathWalkingMode = 0;
m_unk0x0e = 0; m_animationAtCurrentBoundary = FALSE;
m_whichAnim = 0; m_reassemblyAnimation = e_none;
m_assAnim = NULL; m_assAnim = NULL;
m_disAnim = NULL; m_disAnim = NULL;
m_unk0x15 = 0; m_hitBlockCounter = 0;
} }
// FUNCTION: LEGO1 0x1002a6b0 // FUNCTION: LEGO1 0x1002a6b0
@ -48,19 +48,19 @@ LegoExtraActor::~LegoExtraActor()
} }
// FUNCTION: LEGO1 0x1002a720 // FUNCTION: LEGO1 0x1002a720
MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform) MxU32 LegoExtraActor::StepState(float p_time, Matrix4& p_transform)
{ {
switch (m_actorState & c_maxState) { switch (m_actorState & c_maxState) {
case c_initial: case c_initial:
case c_one: case c_ready:
return TRUE; return TRUE;
case c_two: case c_hit:
m_scheduledTime = p_time + 2000.0f; m_scheduledTime = p_time + 2000.0f;
m_actorState = c_three; m_actorState = c_hitAnimation;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
return FALSE; return FALSE;
case c_three: { case c_hitAnimation: {
Vector3 positionRef(p_transform[3]); Vector3 positionRef(p_transform[3]);
p_transform = m_roi->GetLocal2World(); p_transform = m_roi->GetLocal2World();
@ -89,9 +89,9 @@ MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform)
} }
positionRef = position; positionRef = position;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
VTable0x74(p_transform); ApplyTransform(p_transform);
return FALSE; return FALSE;
} }
else { else {
@ -109,32 +109,32 @@ MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform)
} }
// FUNCTION: LEGO1 0x1002aa90 // FUNCTION: LEGO1 0x1002aa90
void LegoExtraActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) void LegoExtraActor::GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex)
{ {
switch (m_unk0x0c) { switch (m_pathWalkingMode) {
case 1: case 1:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = 1; p_selectedEdgeIndex = 1;
break; break;
case 2: case 2:
p_und1 = FALSE; p_countCounterclockWise = FALSE;
p_und2 = 1; p_selectedEdgeIndex = 1;
break; break;
default: default:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = 1 + SDL_rand(p_und2); p_selectedEdgeIndex = 1 + SDL_rand(p_selectedEdgeIndex);
break; break;
} }
} }
// FUNCTION: LEGO1 0x1002aae0 // FUNCTION: LEGO1 0x1002aae0
MxResult LegoExtraActor::FUN_1002aae0() MxResult LegoExtraActor::SwitchDirection()
{ {
LegoPathBoundary* oldEdge = m_boundary; LegoPathBoundary* oldEdge = m_boundary;
Vector3 rightRef(m_unk0xec[0]); Vector3 rightRef(m_local2World[0]);
Vector3 upRef(m_unk0xec[1]); Vector3 upRef(m_local2World[1]);
Vector3 dirRef(m_unk0xec[2]); Vector3 dirRef(m_local2World[2]);
Vector3 positionRef(m_unk0xec[3]); Vector3 positionRef(m_local2World[3]);
dirRef *= -1.0f; dirRef *= -1.0f;
rightRef.EqualsCross(upRef, dirRef); rightRef.EqualsCross(upRef, dirRef);
@ -150,23 +150,23 @@ MxResult LegoExtraActor::FUN_1002aae0()
m_boundary = oldEdge; m_boundary = oldEdge;
} }
LegoPathActor::VTable0x9c(); LegoPathActor::CalculateSpline();
return SUCCESS; return SUCCESS;
} }
inline void LegoExtraActor::FUN_1002ad8a() inline void LegoExtraActor::InitializeReassemblyAnim()
{ {
LegoWorld* w = CurrentWorld(); LegoWorld* w = CurrentWorld();
if (g_unk0x100f31d0 != w) { if (g_reassemblyAnimWorld != w) {
g_unk0x100f31d0 = w; g_reassemblyAnimWorld = w;
m_assAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01"); m_assAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01");
m_disAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01"); m_disAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01");
} }
if (!m_assAnim) { if (!m_assAnim) {
MxS32 index = 0; MxS32 index = 0;
m_assAnimP->FUN_1006d680(this, -20.0f); m_assAnimP->CreateROIAndBuildMap(this, -20.0f);
for (MxS32 i = 0; i < m_animMaps.size(); i++) { for (MxS32 i = 0; i < m_animMaps.size(); i++) {
if (m_animMaps[i]->GetWorldSpeed() == -20.0f) { if (m_animMaps[i]->GetWorldSpeed() == -20.0f) {
@ -178,7 +178,7 @@ inline void LegoExtraActor::FUN_1002ad8a()
if (!m_disAnim) { if (!m_disAnim) {
MxS32 index = 0; MxS32 index = 0;
m_disAnimP->FUN_1006d680(this, -21.0f); m_disAnimP->CreateROIAndBuildMap(this, -21.0f);
for (MxS32 i = 0; i < m_animMaps.size(); i++) { for (MxS32 i = 0; i < m_animMaps.size(); i++) {
if (m_animMaps[i]->GetWorldSpeed() == -21.0f) { if (m_animMaps[i]->GetWorldSpeed() == -21.0f) {
@ -198,26 +198,26 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
} }
if (p_bool) { if (p_bool) {
if (m_unk0x15 != 0) { if (m_hitBlockCounter != 0) {
return FAILURE; return FAILURE;
} }
m_unk0x15 = 100; m_hitBlockCounter = 100;
FUN_1002aae0(); SwitchDirection();
} }
else { else {
MxU32 b = FALSE; MxU32 b = FALSE;
if (++g_unk0x100f31dc % 2 == 0) { if (++g_hitCounter % 2 == 0) {
MxMatrix matrix(p_actor->GetROI()->GetLocal2World()); MxMatrix otherActorLocal(p_actor->GetROI()->GetLocal2World());
MxMatrix matrix2(m_roi->GetLocal2World()); MxMatrix local(m_roi->GetLocal2World());
m_unk0x18 = matrix2; m_localBeforeHit = local;
Vector3 positionRef(matrix2[3]); Vector3 positionRef(local[3]);
Mx3DPointFloat dir(matrix[2]); Mx3DPointFloat otherActorDir(otherActorLocal[2]);
dir *= 2.0f; otherActorDir *= 2.0f;
positionRef += dir; positionRef += otherActorDir;
for (MxS32 i = 0; i < m_boundary->GetNumEdges(); i++) { for (MxS32 i = 0; i < m_boundary->GetNumEdges(); i++) {
Mx4DPointFloat* normal = m_boundary->GetEdgeNormal(i); Mx4DPointFloat* normal = m_boundary->GetEdgeNormal(i);
@ -229,9 +229,9 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
} }
if (!b) { if (!b) {
m_roi->SetLocal2World(matrix2); m_roi->SetLocal2World(local);
m_roi->WrappedUpdateWorldData(); m_roi->WrappedUpdateWorldData();
FUN_1002ad8a(); InitializeReassemblyAnim();
assert(m_roi); assert(m_roi);
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE);
@ -242,8 +242,8 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
m_prevWorldSpeed = GetWorldSpeed(); m_prevWorldSpeed = GetWorldSpeed();
VTable0xc4(); VTable0xc4();
SetWorldSpeed(0); SetWorldSpeed(0);
m_whichAnim = 1; m_reassemblyAnimation = e_disassemble;
SetActorState(c_one | c_noCollide); SetActorState(c_ready | c_noCollide);
} }
} }
@ -255,7 +255,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
EmitGameEvent(e_hitActor); EmitGameEvent(e_hitActor);
} }
VTable0xc4(); VTable0xc4();
SetActorState(c_two | c_noCollide); SetActorState(c_hit | c_noCollide);
Mx3DPointFloat dir = p_actor->GetWorldDirection(); Mx3DPointFloat dir = p_actor->GetWorldDirection();
MxMatrix matrix3 = MxMatrix(roi->GetLocal2World()); MxMatrix matrix3 = MxMatrix(roi->GetLocal2World());
Vector3 positionRef(matrix3[3]); Vector3 positionRef(matrix3[3]);
@ -278,25 +278,25 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
} }
// FUNCTION: LEGO1 0x1002b290 // FUNCTION: LEGO1 0x1002b290
MxResult LegoExtraActor::VTable0x9c() MxResult LegoExtraActor::CalculateSpline()
{ {
LegoPathBoundary* oldBoundary = m_boundary; LegoPathBoundary* oldBoundary = m_boundary;
MxResult result = LegoPathActor::VTable0x9c(); MxResult result = LegoPathActor::CalculateSpline();
if (m_boundary != oldBoundary) { if (m_boundary != oldBoundary) {
MxU32 b = FALSE; MxU32 foundAnimation = FALSE;
LegoAnimPresenterSet& presenters = m_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = m_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) { for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) {
MxU32 roiMapSize; MxU32 roiMapSize;
if ((*it)->GetROIMap(roiMapSize)) { if ((*it)->GetROIMap(roiMapSize)) {
b = TRUE; foundAnimation = TRUE;
break; break;
} }
} }
if (b) { if (foundAnimation) {
m_unk0x0e = 1; m_animationAtCurrentBoundary = TRUE;
m_prevWorldSpeed = GetWorldSpeed(); m_prevWorldSpeed = GetWorldSpeed();
SetWorldSpeed(0); SetWorldSpeed(0);
} }
@ -308,21 +308,21 @@ MxResult LegoExtraActor::VTable0x9c()
// FUNCTION: LEGO1 0x1002b370 // FUNCTION: LEGO1 0x1002b370
void LegoExtraActor::Restart() void LegoExtraActor::Restart()
{ {
if (m_unk0x0e != 0) { if (m_animationAtCurrentBoundary != 0) {
MxU32 b = FALSE; MxU32 foundAnimation = FALSE;
LegoAnimPresenterSet& presenters = m_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = m_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) { for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) {
MxU32 roiMapSize; MxU32 roiMapSize;
if ((*it)->GetROIMap(roiMapSize)) { if ((*it)->GetROIMap(roiMapSize)) {
b = TRUE; foundAnimation = TRUE;
break; break;
} }
} }
if (!b) { if (!foundAnimation) {
SetWorldSpeed(m_prevWorldSpeed); SetWorldSpeed(m_prevWorldSpeed);
m_unk0x0e = 0; m_animationAtCurrentBoundary = FALSE;
} }
} }
} }
@ -332,14 +332,14 @@ void LegoExtraActor::Animate(float p_time)
{ {
LegoAnimActorStruct* laas = NULL; LegoAnimActorStruct* laas = NULL;
switch (m_whichAnim) { switch (m_reassemblyAnimation) {
case 0: case e_none:
LegoAnimActor::Animate(p_time); LegoAnimActor::Animate(p_time);
break; break;
case 1: case e_disassemble:
if (m_scheduledTime < p_time) { if (m_scheduledTime < p_time) {
m_whichAnim = 2; m_reassemblyAnimation = e_assemble;
m_actorState = c_one | c_noCollide; m_actorState = c_ready | c_noCollide;
m_scheduledTime = m_assAnim->GetDuration() + p_time; m_scheduledTime = m_assAnim->GetDuration() + p_time;
break; break;
} }
@ -347,13 +347,13 @@ void LegoExtraActor::Animate(float p_time)
laas = m_disAnim; laas = m_disAnim;
break; break;
} }
case 2: case e_assemble:
if (m_scheduledTime < p_time) { if (m_scheduledTime < p_time) {
m_whichAnim = 0; m_reassemblyAnimation = e_none;
m_actorState = c_initial; m_actorState = c_initial;
SetWorldSpeed(m_prevWorldSpeed); SetWorldSpeed(m_prevWorldSpeed);
m_roi->SetLocal2World(m_unk0x18); m_roi->SetLocal2World(m_localBeforeHit);
m_lastTime = p_time; m_transformTime = p_time;
break; break;
} }
else { else {
@ -385,10 +385,10 @@ void LegoExtraActor::Animate(float p_time)
} }
// FUNCTION: LEGO1 0x1002b5d0 // FUNCTION: LEGO1 0x1002b5d0
void LegoExtraActor::VTable0x74(Matrix4& p_transform) void LegoExtraActor::ApplyTransform(Matrix4& p_transform)
{ {
if (m_whichAnim == 0) { if (m_reassemblyAnimation == e_none) {
LegoAnimActor::VTable0x74(p_transform); LegoAnimActor::ApplyTransform(p_transform);
} }
} }
@ -415,32 +415,32 @@ void LegoExtraActor::VTable0xc4()
if (b) { if (b) {
float duration = m_animMaps[m_curAnim]->GetDuration(); float duration = m_animMaps[m_curAnim]->GetDuration();
MxMatrix matrix(m_unk0xec); MxMatrix matrix(m_local2World);
LegoAnimActor::AnimateWithTransform(duration, matrix); LegoAnimActor::AnimateWithTransform(duration, matrix);
} }
} }
} }
// FUNCTION: LEGO1 0x1002b6f0 // FUNCTION: LEGO1 0x1002b6f0
MxS32 LegoExtraActor::VTable0x68(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3) MxS32 LegoExtraActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint)
{ {
return LegoPathActor::VTable0x68(p_point1, p_point2, p_point3); return LegoPathActor::CheckIntersections(p_rayOrigin, p_rayEnd, p_intersectionPoint);
} }
// FUNCTION: LEGO1 0x1002b980 // FUNCTION: LEGO1 0x1002b980
inline MxU32 LegoExtraActor::VTable0x6c( inline MxU32 LegoExtraActor::CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) )
{ {
LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = p_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) {
if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) {
return 1; return 1;
} }
} }
@ -459,14 +459,14 @@ inline MxU32 LegoExtraActor::VTable0x6c(
if (actor->GetUserNavFlag()) { if (actor->GetUserNavFlag()) {
MxMatrix local2world = roi->GetLocal2World(); MxMatrix local2world = roi->GetLocal2World();
Vector3 local60(local2world[3]); Vector3 local60(local2world[3]);
Mx3DPointFloat local54(p_v1); Mx3DPointFloat local54(p_rayOrigin);
local54 -= local60; local54 -= local60;
float local1c = p_v2.Dot(p_v2, p_v2); float local1c = p_rayDirection.Dot(p_rayDirection, p_rayDirection);
float local24 = p_v2.Dot(p_v2, local54) * 2.0f; float local24 = p_rayDirection.Dot(p_rayDirection, local54) * 2.0f;
float local20 = local54.Dot(local54, local54); float local20 = local54.Dot(local54, local54);
if (m_unk0x15 != 0 && local20 < 10.0f) { if (m_hitBlockCounter != 0 && local20 < 10.0f) {
return 0; return 0;
} }
@ -493,9 +493,10 @@ inline MxU32 LegoExtraActor::VTable0x6c(
local1cX = local40; local1cX = local40;
} }
if ((local20X >= 0.0f && local20X <= p_f1) || (local1cX >= 0.0f && local1cX <= p_f1) || if ((local20X >= 0.0f && local20X <= p_rayLength) ||
(local20X <= -0.01 && p_f1 + 0.01 <= local1cX)) { (local1cX >= 0.0f && local1cX <= p_rayLength) ||
p_v3 = p_v1; (local20X <= -0.01 && p_rayLength + 0.01 <= local1cX)) {
p_intersectionPoint = p_rayOrigin;
if (HitActor(actor, TRUE) < 0) { if (HitActor(actor, TRUE) < 0) {
return 0; return 0;
@ -508,7 +509,14 @@ inline MxU32 LegoExtraActor::VTable0x6c(
} }
} }
else { else {
if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { if (roi->Intersect(
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->GetCollideBox()
)) {
if (HitActor(actor, TRUE) < 0) { if (HitActor(actor, TRUE) < 0) {
return 0; return 0;
} }
@ -522,8 +530,8 @@ inline MxU32 LegoExtraActor::VTable0x6c(
} }
} }
if (m_unk0x15 != 0) { if (m_hitBlockCounter != 0) {
m_unk0x15--; m_hitBlockCounter--;
} }
return 0; return 0;

View File

@ -45,18 +45,18 @@ LegoPathActor::LegoPathActor()
{ {
m_boundary = NULL; m_boundary = NULL;
m_actorTime = 0; m_actorTime = 0;
m_lastTime = 0; m_transformTime = 0;
m_unk0x7c = 0; m_traveledDistance = 0;
m_userNavFlag = FALSE; m_userNavFlag = FALSE;
m_actorState = c_initial; m_actorState = c_initial;
m_grec = NULL; m_grec = NULL;
m_pathController = NULL; m_pathController = NULL;
m_collideBox = FALSE; m_collideBox = FALSE;
m_unk0x148 = 0; m_canRotate = 0;
m_unk0x14c = 0; m_lastRotationAngle = 0;
m_unk0x140 = 0.0099999999f; m_wallHitDirectionFactor = 0.0099999999f;
m_unk0x144 = 0.8f; m_wallHitDampening = 0.8f;
m_unk0x150 = 2.0f; m_linearRotationRatio = 2.0f;
} }
// FUNCTION: LEGO1 0x1002d820 // FUNCTION: LEGO1 0x1002d820
@ -70,19 +70,24 @@ LegoPathActor::~LegoPathActor()
// FUNCTION: LEGO1 0x1002d8d0 // FUNCTION: LEGO1 0x1002d8d0
// FUNCTION: BETA10 0x100ae8cd // FUNCTION: BETA10 0x100ae8cd
MxResult LegoPathActor::VTable0x80(const Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, Vector3& p_point4) MxResult LegoPathActor::SetSpline(
const Vector3& p_start,
Vector3& p_tangentAtStart,
Vector3& p_end,
Vector3& p_tangentAtEnd
)
{ {
Mx3DPointFloat p1, p2, p3; Mx3DPointFloat length, tangentAtStart, tangentAtEnd;
p1 = p_point3; length = p_end;
p1 -= p_point1; length -= p_start;
m_BADuration = p1.LenSquared(); m_BADuration = length.LenSquared();
if (m_BADuration > 0.0f) { if (m_BADuration > 0.0f) {
m_BADuration = sqrtf(m_BADuration); m_BADuration = sqrtf(m_BADuration);
p2 = p_point2; tangentAtStart = p_tangentAtStart;
p3 = p_point4; tangentAtEnd = p_tangentAtEnd;
m_unk0x8c.FUN_1009a140(p_point1, p2, p_point3, p3); m_spline.SetSpline(p_start, tangentAtStart, p_end, tangentAtEnd);
m_BADuration /= 0.001; m_BADuration /= 0.001;
return SUCCESS; return SUCCESS;
} }
@ -94,7 +99,7 @@ MxResult LegoPathActor::VTable0x80(const Vector3& p_point1, Vector3& p_point2, V
// FUNCTION: LEGO1 0x1002d9c0 // FUNCTION: LEGO1 0x1002d9c0
// FUNCTION: BETA10 0x100ae9da // FUNCTION: BETA10 0x100ae9da
MxResult LegoPathActor::VTable0x88( MxResult LegoPathActor::SetTransformAndDestinationFromEdge(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
float p_time, float p_time,
LegoEdge& p_srcEdge, LegoEdge& p_srcEdge,
@ -108,29 +113,29 @@ MxResult LegoPathActor::VTable0x88(
Vector3* v3 = p_destEdge.CWVertex(*p_boundary); Vector3* v3 = p_destEdge.CWVertex(*p_boundary);
Vector3* v4 = p_destEdge.CCWVertex(*p_boundary); Vector3* v4 = p_destEdge.CCWVertex(*p_boundary);
Mx3DPointFloat p1, p2, p3, p4, p5; Mx3DPointFloat start, end, destNormal, startDirection, endDirection;
p1 = *v2; start = *v2;
p1 -= *v1; start -= *v1;
p1 *= p_srcScale; start *= p_srcScale;
p1 += *v1; start += *v1;
p2 = *v4; end = *v4;
p2 -= *v3; end -= *v3;
p2 *= p_destScale; end *= p_destScale;
p2 += *v3; end += *v3;
m_boundary = p_boundary; m_boundary = p_boundary;
m_destEdge = &p_destEdge; m_destEdge = &p_destEdge;
m_unk0xe4 = p_destScale; m_destScale = p_destScale;
m_unk0x7c = 0; m_traveledDistance = 0;
m_lastTime = p_time; m_transformTime = p_time;
m_actorTime = p_time; m_actorTime = p_time;
p_destEdge.GetFaceNormal(*p_boundary, p3); p_destEdge.GetFaceNormal(*p_boundary, destNormal);
p4 = p2; startDirection = end;
p4 -= p1; startDirection -= start;
p4.Unitize(); startDirection.Unitize();
MxMatrix matrix; MxMatrix matrix;
Vector3 pos(matrix[3]); Vector3 pos(matrix[3]);
@ -139,8 +144,8 @@ MxResult LegoPathActor::VTable0x88(
Vector3 right(matrix[0]); Vector3 right(matrix[0]);
matrix.SetIdentity(); matrix.SetIdentity();
pos = p1; pos = start;
dir = p4; dir = startDirection;
up = *m_boundary->GetUp(); up = *m_boundary->GetUp();
if (!m_cameraFlag || !m_userNavFlag) { if (!m_cameraFlag || !m_userNavFlag) {
@ -151,10 +156,10 @@ MxResult LegoPathActor::VTable0x88(
m_roi->UpdateTransformationRelativeToParent(matrix); m_roi->UpdateTransformationRelativeToParent(matrix);
if (!m_cameraFlag || !m_userNavFlag) { if (!m_cameraFlag || !m_userNavFlag) {
p5.EqualsCross(*p_boundary->GetUp(), p3); endDirection.EqualsCross(*p_boundary->GetUp(), destNormal);
p5.Unitize(); endDirection.Unitize();
if (VTable0x80(p1, p4, p2, p5) == SUCCESS) { if (SetSpline(start, startDirection, end, endDirection) == SUCCESS) {
m_boundary->AddActor(this); m_boundary->AddActor(this);
} }
else { else {
@ -166,17 +171,17 @@ MxResult LegoPathActor::VTable0x88(
TransformPointOfView(); TransformPointOfView();
} }
m_unk0xec = m_roi->GetLocal2World(); m_local2World = m_roi->GetLocal2World();
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x1002de10 // FUNCTION: LEGO1 0x1002de10
// FUNCTION: BETA10 0x100aee61 // FUNCTION: BETA10 0x100aee61
MxResult LegoPathActor::VTable0x84( MxResult LegoPathActor::SetTransformAndDestinationFromPoints(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
float p_time, float p_time,
Vector3& p_p1, Vector3& p_start,
Vector3& p_p4, Vector3& p_direction,
LegoOrientedEdge* p_destEdge, LegoOrientedEdge* p_destEdge,
float p_destScale float p_destScale
) )
@ -188,20 +193,20 @@ MxResult LegoPathActor::VTable0x84(
assert(v3 && v4); assert(v3 && v4);
Mx3DPointFloat p2, p3, p5; Mx3DPointFloat end, destNormal, endDirection;
p2 = *v4; end = *v4;
p2 -= *v3; end -= *v3;
p2 *= p_destScale; end *= p_destScale;
p2 += *v3; end += *v3;
m_boundary = p_boundary; m_boundary = p_boundary;
m_destEdge = p_destEdge; m_destEdge = p_destEdge;
m_unk0xe4 = p_destScale; m_destScale = p_destScale;
m_unk0x7c = 0; m_traveledDistance = 0;
m_lastTime = p_time; m_transformTime = p_time;
m_actorTime = p_time; m_actorTime = p_time;
p_destEdge->GetFaceNormal(*p_boundary, p3); p_destEdge->GetFaceNormal(*p_boundary, destNormal);
MxMatrix matrix; MxMatrix matrix;
Vector3 pos(matrix[3]); Vector3 pos(matrix[3]);
@ -210,8 +215,8 @@ MxResult LegoPathActor::VTable0x84(
Vector3 right(matrix[0]); Vector3 right(matrix[0]);
matrix.SetIdentity(); matrix.SetIdentity();
pos = p_p1; pos = p_start;
dir = p_p4; dir = p_direction;
up = *m_boundary->GetUp(); up = *m_boundary->GetUp();
if (!m_cameraFlag || !m_userNavFlag) { if (!m_cameraFlag || !m_userNavFlag) {
@ -226,10 +231,10 @@ MxResult LegoPathActor::VTable0x84(
TransformPointOfView(); TransformPointOfView();
} }
else { else {
p5.EqualsCross(*p_boundary->GetUp(), p3); endDirection.EqualsCross(*p_boundary->GetUp(), destNormal);
p5.Unitize(); endDirection.Unitize();
if (VTable0x80(p_p1, p_p4, p2, p5) != SUCCESS) { if (SetSpline(p_start, p_direction, end, endDirection) != SUCCESS) {
MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName()); MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName());
return FAILURE; return FAILURE;
} }
@ -237,57 +242,59 @@ MxResult LegoPathActor::VTable0x84(
m_boundary->AddActor(this); m_boundary->AddActor(this);
} }
m_unk0xec = m_roi->GetLocal2World(); m_local2World = m_roi->GetLocal2World();
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x1002e100 // FUNCTION: LEGO1 0x1002e100
// FUNCTION: BETA10 0x100b0520 // FUNCTION: BETA10 0x100b0520
MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) MxS32 LegoPathActor::CalculateTransform(float p_time, Matrix4& p_transform)
{ {
if (m_userNavFlag && m_actorState == c_initial) { if (m_userNavFlag && m_actorState == c_initial) {
m_lastTime = p_time; m_transformTime = p_time;
Mx3DPointFloat p1, p2, p3, p4, p5; Mx3DPointFloat newDir, newPos, intersectionPoint, pos, dir;
p5 = Vector3(m_roi->GetWorldDirection()); dir = Vector3(m_roi->GetWorldDirection());
p4 = Vector3(m_roi->GetWorldPosition()); pos = Vector3(m_roi->GetWorldPosition());
LegoNavController* nav = NavController(); LegoNavController* nav = NavController();
assert(nav); assert(nav);
m_worldSpeed = nav->GetLinearVel(); m_worldSpeed = nav->GetLinearVel();
if (nav->CalculateNewPosDir(p4, p5, p2, p1, m_boundary->GetUp())) { if (nav->CalculateNewPosDir(pos, dir, newPos, newDir, m_boundary->GetUp())) {
Mx3DPointFloat p6; Mx3DPointFloat newPosCopy;
p6 = p2; newPosCopy = newPos;
MxS32 result = 0; MxS32 result = 0;
m_unk0xe9 = m_boundary->Intersect(m_roi->GetWorldBoundingSphere().Radius(), p4, p2, p3, m_destEdge); m_finishedTravel =
if (m_unk0xe9 == -1) { m_boundary
->Intersect(m_roi->GetWorldBoundingSphere().Radius(), pos, newPos, intersectionPoint, m_destEdge);
if (m_finishedTravel == -1) {
MxTrace("Intersect returned -1\n"); MxTrace("Intersect returned -1\n");
return -1; return -1;
} }
else { else {
if (m_unk0xe9 != 0) { if (m_finishedTravel != FALSE) {
p2 = p3; newPos = intersectionPoint;
} }
} }
result = VTable0x68(p4, p2, p3); result = CheckIntersections(pos, newPos, intersectionPoint);
if (result > 0) { if (result > 0) {
p2 = p4; newPos = pos;
m_unk0xe9 = 0; m_finishedTravel = FALSE;
result = 0; result = 0;
} }
else { else {
m_boundary->CheckAndCallPathTriggers(p4, p2, this); m_boundary->CheckAndCallPathTriggers(pos, newPos, this);
} }
LegoPathBoundary* oldBoundary = m_boundary; LegoPathBoundary* oldBoundary = m_boundary;
if (m_unk0xe9 != 0) { if (m_finishedTravel != FALSE) {
VTable0x9c(); CalculateSpline();
if (m_boundary == oldBoundary) { if (m_boundary == oldBoundary) {
MxLong time = Timer()->GetTime(); MxLong time = Timer()->GetTime();
@ -301,15 +308,15 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
} }
} }
m_worldSpeed *= m_unk0x144; m_worldSpeed *= m_wallHitDampening;
nav->SetLinearVel(m_worldSpeed); nav->SetLinearVel(m_worldSpeed);
Mx3DPointFloat p7(p2); Mx3DPointFloat newPosDelta(newPos);
p7 -= p6; newPosDelta -= newPosCopy;
if (p7.Unitize() == 0) { if (newPosDelta.Unitize() == 0) {
float f = sqrt(p1.LenSquared()) * m_unk0x140; float f = sqrt(newDir.LenSquared()) * m_wallHitDirectionFactor;
p7 *= f; newPosDelta *= f;
p1 += p7; newDir += newPosDelta;
} }
} }
} }
@ -321,7 +328,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
Vector3 dir(p_transform[2]); Vector3 dir(p_transform[2]);
Vector3 pos(p_transform[3]); Vector3 pos(p_transform[3]);
dir = p1; dir = newDir;
up = *m_boundary->GetUp(); up = *m_boundary->GetUp();
right.EqualsCross(up, dir); right.EqualsCross(up, dir);
@ -329,7 +336,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
assert(res == 0); assert(res == 0);
dir.EqualsCross(right, up); dir.EqualsCross(right, up);
pos = p2; pos = newPos;
return result; return result;
} }
else { else {
@ -337,47 +344,47 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
} }
} }
else if (p_time >= 0 && m_worldSpeed > 0) { else if (p_time >= 0 && m_worldSpeed > 0) {
float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; float endTime = (m_BADuration - m_traveledDistance) / m_worldSpeed + m_transformTime;
if (f < p_time) { if (endTime < p_time) {
m_unk0x7c = m_BADuration; m_traveledDistance = m_BADuration;
m_unk0xe9 = 1; m_finishedTravel = TRUE;
} }
else { else {
f = p_time; endTime = p_time;
m_unk0x7c += (f - m_lastTime) * m_worldSpeed; m_traveledDistance += (endTime - m_transformTime) * m_worldSpeed;
m_unk0xe9 = 0; m_finishedTravel = FALSE;
} }
m_actorTime += (f - m_lastTime) * m_worldSpeed; m_actorTime += (endTime - m_transformTime) * m_worldSpeed;
m_lastTime = f; m_transformTime = endTime;
p_transform.SetIdentity(); p_transform.SetIdentity();
LegoResult r; LegoResult r;
if (m_userNavFlag) { if (m_userNavFlag) {
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 0); r = m_spline.Evaluate(m_traveledDistance / m_BADuration, p_transform, *m_boundary->GetUp(), FALSE);
} }
else { else {
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 1); r = m_spline.Evaluate(m_traveledDistance / m_BADuration, p_transform, *m_boundary->GetUp(), TRUE);
} }
assert(r == 0); // SUCCESS assert(r == 0); // SUCCESS
Vector3 pos1(p_transform[3]); Vector3 end(p_transform[3]);
Vector3 pos2(m_unk0xec[3]); Vector3 origin(m_local2World[3]);
Mx3DPointFloat p1; Mx3DPointFloat p1;
if (VTable0x68(pos2, pos1, p1) > 0) { if (CheckIntersections(origin, end, p1) > 0) {
m_lastTime = p_time; m_transformTime = p_time;
return 1; return 1;
} }
else { else {
m_boundary->CheckAndCallPathTriggers(pos2, pos1, this); m_boundary->CheckAndCallPathTriggers(origin, end, this);
pos2 = pos1; origin = end;
} }
if (m_unk0xe9 != 0) { if (m_finishedTravel != FALSE) {
VTable0x9c(); CalculateSpline();
} }
} }
else { else {
@ -389,7 +396,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
// FUNCTION: LEGO1 0x1002e740 // FUNCTION: LEGO1 0x1002e740
// FUNCTION: BETA10 0x100b0f70 // FUNCTION: BETA10 0x100b0f70
void LegoPathActor::VTable0x74(Matrix4& p_transform) void LegoPathActor::ApplyTransform(Matrix4& p_transform)
{ {
if (m_userNavFlag) { if (m_userNavFlag) {
m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(p_transform); m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(p_transform);
@ -410,69 +417,70 @@ void LegoPathActor::VTable0x74(Matrix4& p_transform)
void LegoPathActor::Animate(float p_time) void LegoPathActor::Animate(float p_time)
{ {
MxMatrix transform; MxMatrix transform;
MxU32 b = FALSE; MxU32 applyTransform = FALSE;
while (m_lastTime < p_time) { while (m_transformTime < p_time) {
if (m_actorState != c_initial && !VTable0x90(p_time, transform)) { if (m_actorState != c_initial && !StepState(p_time, transform)) {
return; return;
} }
if (VTable0x8c(p_time, transform) != 0) { if (CalculateTransform(p_time, transform) != 0) {
break; break;
} }
m_unk0xec = transform; m_local2World = transform;
b = TRUE; applyTransform = TRUE;
if (m_unk0xe9 != 0) { if (m_finishedTravel != FALSE) {
break; break;
} }
} }
if (m_userNavFlag && m_unk0x148) { if (m_userNavFlag && m_canRotate) {
LegoNavController* nav = NavController(); LegoNavController* nav = NavController();
float vel = (nav->GetLinearVel() > 0) float vel =
? -(nav->GetRotationalVel() / (nav->GetMaxLinearVel() * m_unk0x150) * nav->GetLinearVel()) (nav->GetLinearVel() > 0)
: 0; ? -(nav->GetRotationalVel() / (nav->GetMaxLinearVel() * m_linearRotationRatio) * nav->GetLinearVel())
: 0;
if ((MxS32) vel != m_unk0x14c) { if ((MxS32) vel != m_lastRotationAngle) {
m_unk0x14c = vel; m_lastRotationAngle = vel;
LegoWorld* world = CurrentWorld(); LegoWorld* world = CurrentWorld();
if (world) { if (world) {
world->GetCameraController()->RotateZ(DTOR(m_unk0x14c)); world->GetCameraController()->RotateZ(DTOR(m_lastRotationAngle));
} }
} }
} }
if (b) { if (applyTransform) {
VTable0x74(transform); ApplyTransform(transform);
} }
} }
// FUNCTION: LEGO1 0x1002e8b0 // FUNCTION: LEGO1 0x1002e8b0
// FUNCTION: BETA10 0x100af2f7 // FUNCTION: BETA10 0x100af2f7
void LegoPathActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) void LegoPathActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_scale)
{ {
assert(m_boundary); assert(m_boundary);
m_boundary->SwitchBoundary(this, p_boundary, p_edge, p_unk0xe4); m_boundary->SwitchBoundary(this, p_boundary, p_edge, p_scale);
} }
// FUNCTION: LEGO1 0x1002e8d0 // FUNCTION: LEGO1 0x1002e8d0
// FUNCTION: BETA10 0x100b1010 // FUNCTION: BETA10 0x100b1010
MxU32 LegoPathActor::VTable0x6c( MxU32 LegoPathActor::CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) )
{ {
LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = p_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) {
if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) {
return 1; return 1;
} }
} }
@ -488,7 +496,14 @@ MxU32 LegoPathActor::VTable0x6c(
LegoROI* roi = actor->GetROI(); LegoROI* roi = actor->GetROI();
if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) { if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) {
if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->m_collideBox)) { if (roi->Intersect(
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->m_collideBox
)) {
HitActor(actor, TRUE); HitActor(actor, TRUE);
actor->HitActor(this, FALSE); actor->HitActor(this, FALSE);
return 2; return 2;
@ -501,26 +516,33 @@ MxU32 LegoPathActor::VTable0x6c(
return 0; return 0;
} }
inline MxU32 LegoPathActor::FUN_1002edd0( inline MxU32 LegoPathActor::CheckIntersectionBothFaces(
list<LegoPathBoundary*>& p_boundaries, list<LegoPathBoundary*>& p_checkedBoundaries,
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3, Vector3& p_intersectionPoint,
MxS32 p_und MxS32 p_depth
) )
{ {
MxU32 result = VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); MxU32 result = CheckPresenterAndActorIntersections(
p_boundary,
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint
);
if (result != 0) { if (result != 0) {
return result; return result;
} }
p_boundaries.push_back(p_boundary); p_checkedBoundaries.push_back(p_boundary);
if (p_und >= 2) { if (p_depth >= 2) {
return 0; return 0;
} }
@ -532,14 +554,23 @@ inline MxU32 LegoPathActor::FUN_1002edd0(
if (boundary != NULL) { if (boundary != NULL) {
list<LegoPathBoundary*>::const_iterator it; list<LegoPathBoundary*>::const_iterator it;
for (it = p_boundaries.begin(); !(it == p_boundaries.end()); it++) { for (it = p_checkedBoundaries.begin(); !(it == p_checkedBoundaries.end()); it++) {
if ((*it) == boundary) { if ((*it) == boundary) {
break; break;
} }
} }
if (it == p_boundaries.end()) { if (it == p_checkedBoundaries.end()) {
result = FUN_1002edd0(p_boundaries, boundary, p_v1, p_v2, p_f1, p_f2, p_v3, p_und + 1); result = CheckIntersectionBothFaces(
p_checkedBoundaries,
boundary,
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
p_depth + 1
);
if (result != 0) { if (result != 0) {
return result; return result;
@ -553,26 +584,35 @@ inline MxU32 LegoPathActor::FUN_1002edd0(
// FUNCTION: LEGO1 0x1002ebe0 // FUNCTION: LEGO1 0x1002ebe0
// FUNCTION: BETA10 0x100af35e // FUNCTION: BETA10 0x100af35e
MxS32 LegoPathActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) MxS32 LegoPathActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint)
{ {
assert(m_boundary && m_roi); assert(m_boundary && m_roi);
Mx3DPointFloat v2(p_v2); Mx3DPointFloat rayDirection(p_rayEnd);
v2 -= p_v1; rayDirection -= p_rayOrigin;
float len = v2.LenSquared(); float len = rayDirection.LenSquared();
if (len <= 0.001) { if (len <= 0.001) {
return 0; return 0;
} }
len = sqrt((double) len); len = sqrt((double) len);
v2 /= len; rayDirection /= len;
float radius = m_roi->GetWorldBoundingSphere().Radius(); float radius = m_roi->GetWorldBoundingSphere().Radius();
list<LegoPathBoundary*> boundaries; list<LegoPathBoundary*> boundaries;
return FUN_1002edd0(boundaries, m_boundary, p_v1, v2, len, radius, p_v3, 0); return CheckIntersectionBothFaces(
boundaries,
m_boundary,
p_rayOrigin,
rayDirection,
len,
radius,
p_intersectionPoint,
0
);
} }
// FUNCTION: LEGO1 0x1002f020 // FUNCTION: LEGO1 0x1002f020
@ -623,20 +663,21 @@ void LegoPathActor::ParseAction(char* p_extra)
// FUNCTION: LEGO1 0x1002f1b0 // FUNCTION: LEGO1 0x1002f1b0
// FUNCTION: BETA10 0x100af899 // FUNCTION: BETA10 0x100af899
MxResult LegoPathActor::VTable0x9c() MxResult LegoPathActor::CalculateSpline()
{ {
Mx3DPointFloat local34; Mx3DPointFloat targetPosition;
Mx3DPointFloat local48; Mx3DPointFloat endDirection;
MxU32 local1c = 1; MxU32 noPath1 = TRUE;
MxU32 local20 = 1; MxU32 noPath2 = TRUE;
if (m_grec != NULL) { if (m_grec != NULL) {
if (m_grec->GetBit1()) { if (m_grec->HasPath()) {
local1c = 0; noPath1 = FALSE;
local20 = 0; noPath2 = FALSE;
Mx3DPointFloat vec; Mx3DPointFloat vec;
switch (m_pathController->FUN_1004a240(*m_grec, local34, local48, m_unk0xe4, m_destEdge, m_boundary)) { switch (m_pathController
->GetNextPathEdge(*m_grec, targetPosition, endDirection, m_destScale, m_destEdge, m_boundary)) {
case 0: case 0:
case 1: case 1:
break; break;
@ -651,30 +692,30 @@ MxResult LegoPathActor::VTable0x9c()
} }
} }
if (local1c != 0) { if (noPath1 != FALSE) {
SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); SwitchBoundary(m_boundary, m_destEdge, m_destScale);
} }
if (local20 != 0) { if (noPath2 != FALSE) {
Mx3DPointFloat local78; Mx3DPointFloat normal;
assert(m_boundary && m_destEdge); assert(m_boundary && m_destEdge);
Vector3* v1 = m_destEdge->CWVertex(*m_boundary); Vector3* cw = m_destEdge->CWVertex(*m_boundary);
Vector3* v2 = m_destEdge->CCWVertex(*m_boundary); Vector3* ccw = m_destEdge->CCWVertex(*m_boundary);
assert(v1 && v2); assert(cw && ccw);
LERP3(local34, *v1, *v2, m_unk0xe4); LERP3(targetPosition, *cw, *ccw, m_destScale);
m_destEdge->GetFaceNormal(*m_boundary, local78); m_destEdge->GetFaceNormal(*m_boundary, normal);
local48.EqualsCross(*m_boundary->GetUp(), local78); endDirection.EqualsCross(*m_boundary->GetUp(), normal);
local48.Unitize(); endDirection.Unitize();
} }
Vector3 rightRef(m_unk0xec[0]); Vector3 rightRef(m_local2World[0]);
Vector3 upRef(m_unk0xec[1]); Vector3 upRef(m_local2World[1]);
Vector3 dirRef(m_unk0xec[2]); Vector3 dirRef(m_local2World[2]);
upRef = *m_boundary->GetUp(); upRef = *m_boundary->GetUp();
@ -684,74 +725,74 @@ MxResult LegoPathActor::VTable0x9c()
dirRef.EqualsCross(rightRef, upRef); dirRef.EqualsCross(rightRef, upRef);
dirRef.Unitize(); dirRef.Unitize();
Mx3DPointFloat localc0(m_unk0xec[3]); Mx3DPointFloat start(m_local2World[3]);
Mx3DPointFloat local84(m_unk0xec[2]); Mx3DPointFloat direction(m_local2World[2]);
Mx3DPointFloat local70(local34); Mx3DPointFloat startToTarget(targetPosition);
local70 -= localc0; startToTarget -= start;
float len = local70.LenSquared(); float len = startToTarget.LenSquared();
if (len >= 0.0f) { if (len >= 0.0f) {
len = sqrt(len); len = sqrt(len);
local84 *= len; direction *= len;
local48 *= len; endDirection *= len;
} }
if (!m_userNavFlag) { if (!m_userNavFlag) {
local84 *= -1.0f; direction *= -1.0f;
} }
if (VTable0x80(localc0, local84, local34, local48) != SUCCESS) { if (SetSpline(start, direction, targetPosition, endDirection) != SUCCESS) {
MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName()); MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName());
return FAILURE; return FAILURE;
} }
m_unk0x7c = 0.0f; m_traveledDistance = 0.0f;
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x1002f650 // FUNCTION: LEGO1 0x1002f650
// FUNCTION: BETA10 0x100afd67 // FUNCTION: BETA10 0x100afd67
void LegoPathActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) void LegoPathActor::GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex)
{ {
switch (GetActorId()) { switch (GetActorId()) {
case c_pepper: case c_pepper:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = 2; p_selectedEdgeIndex = 2;
break; break;
case c_mama: case c_mama:
p_und1 = FALSE; p_countCounterclockWise = FALSE;
p_und2 = 1; p_selectedEdgeIndex = 1;
break; break;
case c_papa: case c_papa:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = 1; p_selectedEdgeIndex = 1;
break; break;
case c_nick: case c_nick:
case c_brickster: case c_brickster:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = SDL_rand(p_und2) + 1; p_selectedEdgeIndex = SDL_rand(p_selectedEdgeIndex) + 1;
break; break;
case c_laura: case c_laura:
p_und1 = FALSE; p_countCounterclockWise = FALSE;
p_und2 = 2; p_selectedEdgeIndex = 2;
break; break;
default: default:
p_und1 = TRUE; p_countCounterclockWise = TRUE;
p_und2 = 1; p_selectedEdgeIndex = 1;
break; break;
} }
} }
// FUNCTION: LEGO1 0x1002f700 // FUNCTION: LEGO1 0x1002f700
// FUNCTION: BETA10 0x100afe4c // FUNCTION: BETA10 0x100afe4c
void LegoPathActor::VTable0xa8() void LegoPathActor::ApplyLocal2World()
{ {
m_lastTime = Timer()->GetTime(); m_transformTime = Timer()->GetTime();
m_roi->SetLocal2World(m_unk0xec); m_roi->SetLocal2World(m_local2World);
m_roi->WrappedUpdateWorldData(); m_roi->WrappedUpdateWorldData();
if (m_userNavFlag) { if (m_userNavFlag) {
m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0xec); m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(m_local2World);
TransformPointOfView(); TransformPointOfView();
} }
} }

View File

@ -89,7 +89,7 @@ void LegoPathBoundary::SwitchBoundary(
LegoPathActor* p_actor, LegoPathActor* p_actor,
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
float& p_unk0xe4 float& p_scale
) )
{ {
LegoOrientedEdge* e = p_edge; LegoOrientedEdge* e = p_edge;
@ -101,7 +101,7 @@ void LegoPathBoundary::SwitchBoundary(
newBoundary = p_boundary; newBoundary = p_boundary;
} }
MxS32 local10 = 0; MxS32 availableEdgeCount = 0;
MxU8 userNavFlag; MxU8 userNavFlag;
if (e->BETA_1004a830(*newBoundary, 1)) { if (e->BETA_1004a830(*newBoundary, 1)) {
@ -113,38 +113,38 @@ void LegoPathBoundary::SwitchBoundary(
do { do {
p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary); p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary);
LegoPathBoundary* local20 = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); LegoPathBoundary* otherBoundary = (LegoPathBoundary*) p_edge->OtherFace(newBoundary);
if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*local20, 1))) { if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*otherBoundary, 1))) {
local10++; availableEdgeCount++;
} }
} while (p_edge != e); } while (p_edge != e);
MxBool localc = TRUE; MxBool countCounterclockwise = TRUE;
MxS32 local8 = local10 - 1; MxS32 selectedEdgeIndex = availableEdgeCount - 1;
if (local10 <= 1) { if (availableEdgeCount <= 1) {
local8 = 0; selectedEdgeIndex = 0;
} }
else if (local10 == 2) { else if (availableEdgeCount == 2) {
local8 = 1; selectedEdgeIndex = 1;
} }
else { else {
p_actor->VTable0xa4(localc, local8); p_actor->GetWalkingBehavior(countCounterclockwise, selectedEdgeIndex);
} }
while (local8 > 0) { while (selectedEdgeIndex > 0) {
if (localc) { if (countCounterclockwise) {
p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary); p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary);
} }
else { else {
p_edge = (LegoOrientedEdge*) p_edge->GetClockwiseEdge(*newBoundary); p_edge = (LegoOrientedEdge*) p_edge->GetClockwiseEdge(*newBoundary);
} }
LegoPathBoundary* local20 = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); LegoPathBoundary* otherBoundary = (LegoPathBoundary*) p_edge->OtherFace(newBoundary);
if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*local20, 1))) { if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*otherBoundary, 1))) {
local8--; selectedEdgeIndex--;
} }
} }
@ -159,7 +159,7 @@ void LegoPathBoundary::SwitchBoundary(
p_boundary->AddActor(p_actor); p_boundary->AddActor(p_actor);
} }
else { else {
p_unk0xe4 = 1.0 - p_unk0xe4; p_scale = 1.0 - p_scale;
} }
} }
else { else {
@ -176,7 +176,7 @@ void LegoPathBoundary::SwitchBoundary(
p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*p_boundary); p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*p_boundary);
} }
p_unk0xe4 = 1.0 - p_unk0xe4; p_scale = 1.0 - p_scale;
} }
} }
@ -184,127 +184,128 @@ void LegoPathBoundary::SwitchBoundary(
// FUNCTION: BETA10 0x100b1adc // FUNCTION: BETA10 0x100b1adc
MxU32 LegoPathBoundary::Intersect( MxU32 LegoPathBoundary::Intersect(
float p_scale, float p_scale,
Vector3& p_point1, Vector3& p_oldPos,
Vector3& p_point2, Vector3& p_newPos,
Vector3& p_point3, Vector3& p_intersectionPoint,
LegoOrientedEdge*& p_edge LegoOrientedEdge*& p_edge
) )
{ {
LegoOrientedEdge* e = NULL; LegoOrientedEdge* e = NULL;
float localc; float minHitDistance;
MxU32 local10 = 0; MxU32 normalizedCalculated = 0;
float len = 0.0f; float len = 0.0f;
Mx3DPointFloat vec; Mx3DPointFloat direction;
for (MxS32 i = 0; i < m_numEdges; i++) { for (MxS32 i = 0; i < m_numEdges; i++) {
LegoOrientedEdge* edge = (LegoOrientedEdge*) m_edges[i]; LegoOrientedEdge* edge = (LegoOrientedEdge*) m_edges[i];
if (p_point2.Dot(m_edgeNormals[i], p_point2) + m_edgeNormals[i][3] <= -1e-07) { if (p_newPos.Dot(m_edgeNormals[i], p_newPos) + m_edgeNormals[i][3] <= -1e-07) {
if (local10 == 0) { if (normalizedCalculated == FALSE) {
local10 = 1; normalizedCalculated = TRUE;
vec = p_point2; direction = p_newPos;
vec -= p_point1; direction -= p_oldPos;
len = vec.LenSquared(); len = direction.LenSquared();
if (len <= 0.0f) { if (len <= 0.0f) {
return 0; return 0;
} }
len = sqrt(len); len = sqrt(len);
vec /= len; direction /= len;
} }
float dot = vec.Dot(vec, m_edgeNormals[i]); float dot = direction.Dot(direction, m_edgeNormals[i]);
if (dot != 0.0f) { if (dot != 0.0f) {
float local34 = (-m_edgeNormals[i][3] - p_point1.Dot(p_point1, m_edgeNormals[i])) / dot; float hitDistance = (-m_edgeNormals[i][3] - p_oldPos.Dot(p_oldPos, m_edgeNormals[i])) / dot;
if (local34 >= -0.001 && local34 <= len && (e == NULL || local34 < localc)) { if (hitDistance >= -0.001 && hitDistance <= len && (e == NULL || hitDistance < minHitDistance)) {
e = edge; e = edge;
localc = local34; minHitDistance = hitDistance;
} }
} }
} }
} }
if (e != NULL) { if (e != NULL) {
if (localc < 0.0f) { if (minHitDistance < 0.0f) {
localc = 0.0f; minHitDistance = 0.0f;
} }
Mx3DPointFloat local50; Mx3DPointFloat startToPosition;
Mx3DPointFloat local70; Mx3DPointFloat edgeNormal;
Vector3* local5c = e->CWVertex(*this); Vector3* start = e->CWVertex(*this);
p_point3 = vec; p_intersectionPoint = direction;
p_point3 *= localc; p_intersectionPoint *= minHitDistance;
p_point3 += p_point1; p_intersectionPoint += p_oldPos;
local50 = p_point2; startToPosition = p_newPos;
local50 -= *local5c; startToPosition -= *start;
e->GetFaceNormal(*this, local70); e->GetFaceNormal(*this, edgeNormal);
float local58 = local50.Dot(local50, local70); float projection = startToPosition.Dot(startToPosition, edgeNormal);
LegoOrientedEdge* local54 = NULL; LegoOrientedEdge* candidateEdge = NULL;
if (local58 < 0.0f) { if (projection < 0.0f) {
Mx3DPointFloat local84; Mx3DPointFloat candidateEdgeNormal;
for (LegoOrientedEdge* local88 = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); e != local88; for (LegoOrientedEdge* cwEdge = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); e != cwEdge;
local88 = (LegoOrientedEdge*) local88->GetClockwiseEdge(*this)) { cwEdge = (LegoOrientedEdge*) cwEdge->GetClockwiseEdge(*this)) {
local88->GetFaceNormal(*this, local84); cwEdge->GetFaceNormal(*this, candidateEdgeNormal);
if (local84.Dot(local84, local70) <= 0.9) { if (candidateEdgeNormal.Dot(candidateEdgeNormal, edgeNormal) <= 0.9) {
break; break;
} }
Vector3* local90 = local88->CWVertex(*this); Vector3* candidateStart = cwEdge->CWVertex(*this);
Mx3DPointFloat locala4(p_point3); Mx3DPointFloat candidateToIntersection(p_intersectionPoint);
locala4 -= *local90; candidateToIntersection -= *candidateStart;
float local8c = locala4.Dot(locala4, local84); float candidateProjection = candidateToIntersection.Dot(candidateToIntersection, candidateEdgeNormal);
if (local8c > local58 && local8c < local88->m_length) { if (candidateProjection > projection && candidateProjection < cwEdge->m_length) {
local54 = local88; candidateEdge = cwEdge;
local58 = local8c; projection = candidateProjection;
local70 = local84; edgeNormal = candidateEdgeNormal;
local5c = local90; start = candidateStart;
} }
} }
} }
else { else {
if (e->m_length < local58) { if (e->m_length < projection) {
Mx3DPointFloat localbc; Mx3DPointFloat candidateEdgeNormal;
for (LegoOrientedEdge* locala8 = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); e != locala8; for (LegoOrientedEdge* ccwEdge = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); e != ccwEdge;
locala8 = (LegoOrientedEdge*) locala8->GetCounterclockwiseEdge(*this)) { ccwEdge = (LegoOrientedEdge*) ccwEdge->GetCounterclockwiseEdge(*this)) {
locala8->GetFaceNormal(*this, localbc); ccwEdge->GetFaceNormal(*this, candidateEdgeNormal);
if (localbc.Dot(localbc, local70) <= 0.9) { if (candidateEdgeNormal.Dot(candidateEdgeNormal, edgeNormal) <= 0.9) {
break; break;
} }
Vector3* localc4 = locala8->CWVertex(*this); Vector3* candidateStart = ccwEdge->CWVertex(*this);
Mx3DPointFloat locald8(p_point3); Mx3DPointFloat candidateToIntersection(p_intersectionPoint);
locald8 -= *localc4; candidateToIntersection -= *candidateStart;
float localc0 = locald8.Dot(locald8, localbc); float candidateProjection =
candidateToIntersection.Dot(candidateToIntersection, candidateEdgeNormal);
if (localc0 < local58 && localc0 >= 0.0f) { if (candidateProjection < projection && candidateProjection >= 0.0f) {
local54 = locala8; candidateEdge = ccwEdge;
local58 = localc0; projection = candidateProjection;
local70 = localbc; edgeNormal = candidateEdgeNormal;
local5c = localc4; start = candidateStart;
} }
} }
} }
} }
if (local54 != NULL) { if (candidateEdge != NULL) {
e = local54; e = candidateEdge;
} }
if (local58 <= 0.0f) { if (projection <= 0.0f) {
if (!e->GetMask0x03()) { if (!e->GetMask0x03()) {
p_edge = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); p_edge = (LegoOrientedEdge*) e->GetClockwiseEdge(*this);
} }
@ -312,18 +313,18 @@ MxU32 LegoPathBoundary::Intersect(
p_edge = e; p_edge = e;
} }
p_point3 = *local5c; p_intersectionPoint = *start;
return 2; return 2;
} }
else if (local58 > 0.0f && e->m_length > local58) { else if (projection > 0.0f && e->m_length > projection) {
p_point3 = local70; p_intersectionPoint = edgeNormal;
p_point3 *= local58; p_intersectionPoint *= projection;
p_point3 += *local5c; p_intersectionPoint += *start;
p_edge = e; p_edge = e;
return 1; return 1;
} }
else { else {
p_point3 = *e->CCWVertex(*this); p_intersectionPoint = *e->CCWVertex(*this);
if (!e->GetMask0x03()) { if (!e->GetMask0x03()) {
p_edge = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); p_edge = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this);
@ -343,15 +344,15 @@ MxU32 LegoPathBoundary::Intersect(
// FUNCTION: BETA10 0x100b2220 // FUNCTION: BETA10 0x100b2220
MxU32 LegoPathBoundary::AddPresenterIfInRange(LegoAnimPresenter* p_presenter) MxU32 LegoPathBoundary::AddPresenterIfInRange(LegoAnimPresenter* p_presenter)
{ {
Mx3DPointFloat unk0x30; Mx3DPointFloat centerDistance;
unk0x30 = m_centerPoint; centerDistance = m_centerPoint;
unk0x30 -= p_presenter->m_unk0xa8; centerDistance -= p_presenter->m_centerPoint;
float len = unk0x30.LenSquared(); float len = centerDistance.LenSquared();
float local20 = p_presenter->m_unk0xa4 + m_boundingRadius; float radiusSquared = p_presenter->m_boundingRadius + m_boundingRadius;
if (len > 0.001 && len > local20 * local20) { if (len > 0.001 && len > radiusSquared * radiusSquared) {
return 0; return 0;
} }

View File

@ -14,10 +14,10 @@ DECOMP_SIZE_ASSERT(LegoPathController::CtrlBoundary, 0x08)
DECOMP_SIZE_ASSERT(LegoPathController::CtrlEdge, 0x08) DECOMP_SIZE_ASSERT(LegoPathController::CtrlEdge, 0x08)
// GLOBAL: LEGO1 0x100d7cc8 // GLOBAL: LEGO1 0x100d7cc8
MxU32 g_unk0x100d7cc8[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0}; MxU32 g_ctrlEdgesNamesA[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0};
// GLOBAL: LEGO1 0x100d7d08 // GLOBAL: LEGO1 0x100d7d08
MxU32 g_unk0x100d7d08[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; MxU32 g_ctrlEdgesNamesB[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// GLOBAL: LEGO1 0x100f42e8 // GLOBAL: LEGO1 0x100f42e8
// GLOBAL: BETA10 0x101f25f0 // GLOBAL: BETA10 0x101f25f0
@ -28,7 +28,7 @@ LegoPathController::CtrlBoundary* LegoPathController::g_ctrlBoundariesA = NULL;
LegoPathController::CtrlEdge* LegoPathController::g_ctrlEdgesA = NULL; LegoPathController::CtrlEdge* LegoPathController::g_ctrlEdgesA = NULL;
// GLOBAL: LEGO1 0x100f42f0 // GLOBAL: LEGO1 0x100f42f0
const char* LegoPathController::g_unk0x100f42f0[] = { const char* LegoPathController::g_ctrlBoundariesNamesA[] = {
"edg03_21", "edg03_21",
"edg03_23", "edg03_23",
"edg03_30", "edg03_30",
@ -48,7 +48,7 @@ const char* LegoPathController::g_unk0x100f42f0[] = {
}; };
// GLOBAL: LEGO1 0x100f4330 // GLOBAL: LEGO1 0x100f4330
const char* LegoPathController::g_unk0x100f4330[] = { const char* LegoPathController::g_ctrlBoundariesNamesB[] = {
"edg03_06", "edg03_06",
"edg03_21", "edg03_21",
"edg03_30", "edg03_30",
@ -108,23 +108,23 @@ MxResult LegoPathController::Create(
LegoPathBoundary& boundary = m_boundaries[i]; LegoPathBoundary& boundary = m_boundaries[i];
MxS32 j; MxS32 j;
for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesA); j++) {
if (!SDL_strcasecmp(g_unk0x100f42f0[j], boundary.GetName())) { if (!SDL_strcasecmp(g_ctrlBoundariesNamesA[j], boundary.GetName())) {
g_ctrlBoundariesA[j].m_controller = this; g_ctrlBoundariesA[j].m_controller = this;
g_ctrlBoundariesA[j].m_boundary = &boundary; g_ctrlBoundariesA[j].m_boundary = &boundary;
MxU32 edge = g_unk0x100d7cc8[j]; MxU32 edge = g_ctrlEdgesNamesA[j];
g_ctrlEdgesA[j].m_controller = this; g_ctrlEdgesA[j].m_controller = this;
g_ctrlEdgesA[j].m_edge = boundary.GetEdges()[edge]; g_ctrlEdgesA[j].m_edge = boundary.GetEdges()[edge];
} }
} }
for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesB); j++) {
if (!SDL_strcasecmp(g_unk0x100f4330[j], boundary.GetName())) { if (!SDL_strcasecmp(g_ctrlBoundariesNamesB[j], boundary.GetName())) {
g_ctrlBoundariesB[j].m_controller = this; g_ctrlBoundariesB[j].m_controller = this;
g_ctrlBoundariesB[j].m_boundary = &boundary; g_ctrlBoundariesB[j].m_boundary = &boundary;
g_ctrlEdgesB[j].m_controller = this; g_ctrlEdgesB[j].m_controller = this;
g_ctrlEdgesB[j].m_edge = boundary.GetEdges()[g_unk0x100d7d08[j]]; g_ctrlEdgesB[j].m_edge = boundary.GetEdges()[g_ctrlEdgesNamesB[j]];
} }
} }
} }
@ -170,7 +170,7 @@ void LegoPathController::Destroy()
m_numE = 0; m_numE = 0;
MxS32 j; MxS32 j;
for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesA); j++) {
if (g_ctrlBoundariesA[j].m_controller == this) { if (g_ctrlBoundariesA[j].m_controller == this) {
g_ctrlBoundariesA[j].m_controller = NULL; g_ctrlBoundariesA[j].m_controller = NULL;
g_ctrlBoundariesA[j].m_boundary = NULL; g_ctrlBoundariesA[j].m_boundary = NULL;
@ -182,7 +182,7 @@ void LegoPathController::Destroy()
} }
} }
for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesB); j++) {
if (g_ctrlBoundariesB[j].m_controller == this) { if (g_ctrlBoundariesB[j].m_controller == this) {
g_ctrlBoundariesB[j].m_controller = NULL; g_ctrlBoundariesB[j].m_controller = NULL;
g_ctrlBoundariesB[j].m_boundary = NULL; g_ctrlBoundariesB[j].m_boundary = NULL;
@ -199,7 +199,7 @@ void LegoPathController::Destroy()
// FUNCTION: BETA10 0x100b6d60 // FUNCTION: BETA10 0x100b6d60
MxResult LegoPathController::Tickle() MxResult LegoPathController::Tickle()
{ {
FUN_10046970(); AnimateActors();
return SUCCESS; return SUCCESS;
} }
@ -230,8 +230,14 @@ MxResult LegoPathController::PlaceActor(
assert(pSrcE && pDestE); assert(pSrcE && pDestE);
float time = Timer()->GetTime(); float time = Timer()->GetTime();
MxResult result = MxResult result = p_actor->SetTransformAndDestinationFromEdge(
p_actor->VTable0x88(pBoundary, time, *pSrcE, p_srcScale, (LegoOrientedEdge&) *pDestE, p_destScale); pBoundary,
time,
*pSrcE,
p_srcScale,
(LegoOrientedEdge&) *pDestE,
p_destScale
);
if (result != SUCCESS) { if (result != SUCCESS) {
assert(0); assert(0);
@ -305,7 +311,8 @@ MxResult LegoPathController::PlaceActor(
return FAILURE; return FAILURE;
} }
if (p_actor->VTable0x84(boundary, time, p_position, p_direction, edge, 0.5f) == SUCCESS) { if (p_actor->SetTransformAndDestinationFromPoints(boundary, time, p_position, p_direction, edge, 0.5f) ==
SUCCESS) {
p_actor->SetController(this); p_actor->SetController(this);
m_actors.insert(p_actor); m_actors.insert(p_actor);
return SUCCESS; return SUCCESS;
@ -350,7 +357,7 @@ MxResult LegoPathController::RemoveActor(LegoPathActor* p_actor)
// FUNCTION: LEGO1 0x100468f0 // FUNCTION: LEGO1 0x100468f0
// FUNCTION: BETA10 0x100b72f7 // FUNCTION: BETA10 0x100b72f7
void LegoPathController::FUN_100468f0(LegoAnimPresenter* p_presenter) void LegoPathController::AddPresenterIfInRange(LegoAnimPresenter* p_presenter)
{ {
for (MxS32 i = 0; i < m_numL; i++) { for (MxS32 i = 0; i < m_numL; i++) {
if (!(m_boundaries[i].m_flags & LegoWEGEdge::c_bit3)) { if (!(m_boundaries[i].m_flags & LegoWEGEdge::c_bit3)) {
@ -370,7 +377,7 @@ void LegoPathController::RemovePresenterFromBoundaries(LegoAnimPresenter* p_pres
// FUNCTION: LEGO1 0x10046970 // FUNCTION: LEGO1 0x10046970
// FUNCTION: BETA10 0x100b73d8 // FUNCTION: BETA10 0x100b73d8
void LegoPathController::FUN_10046970() void LegoPathController::AnimateActors()
{ {
float time = Timer()->GetTime(); float time = Timer()->GetTime();
@ -388,7 +395,7 @@ void LegoPathController::FUN_10046970()
} }
// FUNCTION: LEGO1 0x10046b30 // FUNCTION: LEGO1 0x10046b30
MxResult LegoPathController::FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL) MxResult LegoPathController::GetBoundaries(LegoPathBoundary*& p_boundaries, MxS32& p_numL)
{ {
p_boundaries = m_boundaries; p_boundaries = m_boundaries;
p_numL = m_numL; p_numL = m_numL;
@ -410,7 +417,7 @@ LegoPathBoundary* LegoPathController::GetPathBoundary(const char* p_name)
// FUNCTION: LEGO1 0x10046bb0 // FUNCTION: LEGO1 0x10046bb0
// FUNCTION: BETA10 0x100b75bc // FUNCTION: BETA10 0x100b75bc
void LegoPathController::FUN_10046bb0(LegoWorld* p_world) void LegoPathController::SetWorld(LegoWorld* p_world)
{ {
for (MxS32 i = 0; i < m_numT; i++) { for (MxS32 i = 0; i < m_numT; i++) {
m_structs[i].SetWorld(p_world); m_structs[i].SetWorld(p_world);
@ -437,10 +444,10 @@ MxResult LegoPathController::Init()
return FAILURE; return FAILURE;
} }
g_ctrlBoundariesA = new CtrlBoundary[sizeOfArray(g_unk0x100f42f0)]; g_ctrlBoundariesA = new CtrlBoundary[sizeOfArray(g_ctrlBoundariesNamesA)];
g_ctrlEdgesA = new CtrlEdge[sizeOfArray(g_unk0x100f42f0)]; g_ctrlEdgesA = new CtrlEdge[sizeOfArray(g_ctrlBoundariesNamesA)];
g_ctrlBoundariesB = new CtrlBoundary[sizeOfArray(g_unk0x100f4330)]; g_ctrlBoundariesB = new CtrlBoundary[sizeOfArray(g_ctrlBoundariesNamesB)];
g_ctrlEdgesB = new CtrlEdge[sizeOfArray(g_unk0x100f4330)]; g_ctrlEdgesB = new CtrlEdge[sizeOfArray(g_ctrlBoundariesNamesB)];
return SUCCESS; return SUCCESS;
} }
@ -765,7 +772,7 @@ MxResult LegoPathController::ReadVector(LegoStorage* p_storage, Mx4DPointFloat&
// FUNCTION: LEGO1 0x10048310 // FUNCTION: LEGO1 0x10048310
// FUNCTION: BETA10 0x100b8911 // FUNCTION: BETA10 0x100b8911
MxResult LegoPathController::FUN_10048310( MxResult LegoPathController::FindPath(
LegoPathEdgeContainer* p_grec, LegoPathEdgeContainer* p_grec,
const Vector3& p_oldPosition, const Vector3& p_oldPosition,
const Vector3& p_oldDirection, const Vector3& p_oldDirection,
@ -774,7 +781,7 @@ MxResult LegoPathController::FUN_10048310(
const Vector3& p_newDirection, const Vector3& p_newDirection,
LegoPathBoundary* p_newBoundary, LegoPathBoundary* p_newBoundary,
LegoU8 p_mask, LegoU8 p_mask,
MxFloat* p_param9 MxFloat* p_distance
) )
{ {
p_grec->m_position = p_newPosition; p_grec->m_position = p_newPosition;
@ -782,22 +789,22 @@ MxResult LegoPathController::FUN_10048310(
p_grec->m_boundary = p_newBoundary; p_grec->m_boundary = p_newBoundary;
if (p_newBoundary == p_oldBoundary) { if (p_newBoundary == p_oldBoundary) {
p_grec->SetBit1(TRUE); p_grec->SetPath(TRUE);
return SUCCESS; return SUCCESS;
} }
list<LegoBEWithFloat> boundaryList; list<LegoBEWithMidpoint> boundaryList;
list<LegoBEWithFloat>::iterator boundaryListIt; list<LegoBEWithMidpoint>::iterator boundaryListIt;
LegoBEWithFloatSet boundarySet; LegoBEWithMidpointSet boundarySet;
LegoBEWithFloatSet::iterator boundarySetItA; LegoBEWithMidpointSet::iterator boundarySetItA;
LegoBEWithFloatSet::iterator boundarySetItB; LegoBEWithMidpointSet::iterator boundarySetItB;
LegoPathCtrlEdgeSet pathCtrlEdgeSet(m_pfsE); LegoPathCtrlEdgeSet pathCtrlEdgeSet(m_pfsE);
MxFloat local14 = 999999.0f; MxFloat minDistance = 999999.0f;
p_grec->SetBit1(FALSE); p_grec->SetPath(FALSE);
for (MxS32 i = 0; i < p_oldBoundary->GetNumEdges(); i++) { for (MxS32 i = 0; i < p_oldBoundary->GetNumEdges(); i++) {
LegoPathCtrlEdge* edge = (LegoPathCtrlEdge*) p_oldBoundary->GetEdges()[i]; LegoPathCtrlEdge* edge = (LegoPathCtrlEdge*) p_oldBoundary->GetEdges()[i];
@ -809,15 +816,16 @@ MxResult LegoPathController::FUN_10048310(
if (p_newBoundary == otherFace) { if (p_newBoundary == otherFace) {
float dist; float dist;
if ((dist = edge->DistanceToMidpoint(p_oldPosition) + edge->DistanceToMidpoint(p_newPosition)) < if ((dist = edge->DistanceToMidpoint(p_oldPosition) + edge->DistanceToMidpoint(p_newPosition)) <
local14) { minDistance) {
local14 = dist; minDistance = dist;
p_grec->erase(p_grec->begin(), p_grec->end()); p_grec->erase(p_grec->begin(), p_grec->end());
p_grec->SetBit1(TRUE); p_grec->SetPath(TRUE);
p_grec->push_back(LegoBoundaryEdge(edge, p_oldBoundary)); p_grec->push_back(LegoBoundaryEdge(edge, p_oldBoundary));
} }
} }
else { else {
boundaryList.push_back(LegoBEWithFloat(edge, p_oldBoundary, edge->DistanceToMidpoint(p_oldPosition)) boundaryList.push_back(
LegoBEWithMidpoint(edge, p_oldBoundary, edge->DistanceToMidpoint(p_oldPosition))
); );
boundarySet.insert(&boundaryList.back()); boundarySet.insert(&boundaryList.back());
} }
@ -827,10 +835,10 @@ MxResult LegoPathController::FUN_10048310(
pathCtrlEdgeSet.erase(edge); pathCtrlEdgeSet.erase(edge);
} }
if (!p_grec->GetBit1()) { if (!p_grec->HasPath()) {
while (pathCtrlEdgeSet.size() > 0) { while (pathCtrlEdgeSet.size() > 0) {
LegoBEWithFloat edgeWithFloat; LegoBEWithMidpoint edgeWithMidpoint;
MxFloat local70 = 999999.0f; MxFloat minDist = 999999.0f;
boundarySetItA = boundarySetItB = boundarySet.begin(); boundarySetItA = boundarySetItB = boundarySet.begin();
@ -855,19 +863,20 @@ MxResult LegoPathController::FUN_10048310(
if (bOther == p_newBoundary) { if (bOther == p_newBoundary) {
shouldRemove = FALSE; shouldRemove = FALSE;
LegoBEWithFloat* pfs = *boundarySetItA; LegoBEWithMidpoint* pfs = *boundarySetItA;
assert(pfs); assert(pfs);
float dist; float dist;
if ((dist = pfs->m_edge->DistanceToMidpoint(p_newPosition) + pfs->m_unk0x0c) < local70) { if ((dist = pfs->m_edge->DistanceToMidpoint(p_newPosition) + pfs->m_distanceToMidpoint) <
edgeWithFloat.m_edge = NULL; minDist) {
local70 = dist; edgeWithMidpoint.m_edge = NULL;
minDist = dist;
// TODO: Match // TODO: Match
if (dist < local14) { if (dist < minDistance) {
local14 = dist; minDistance = dist;
p_grec->erase(p_grec->begin(), p_grec->end()); p_grec->erase(p_grec->begin(), p_grec->end());
p_grec->SetBit1(TRUE); p_grec->SetPath(TRUE);
do { do {
p_grec->push_front(LegoBoundaryEdge(pfs->m_edge, pfs->m_boundary)); p_grec->push_front(LegoBoundaryEdge(pfs->m_edge, pfs->m_boundary));
@ -885,10 +894,10 @@ MxResult LegoPathController::FUN_10048310(
shouldRemove = FALSE; shouldRemove = FALSE;
float dist; float dist;
if ((dist = edge->DistanceBetweenMidpoints(*e) + (*boundarySetItA)->m_unk0x0c) < if ((dist = edge->DistanceBetweenMidpoints(*e) +
local70) { (*boundarySetItA)->m_distanceToMidpoint) < minDist) {
local70 = dist; minDist = dist;
edgeWithFloat = LegoBEWithFloat(edge, bOther, *boundarySetItA, dist); edgeWithMidpoint = LegoBEWithMidpoint(edge, bOther, *boundarySetItA, dist);
} }
} }
} }
@ -909,9 +918,9 @@ MxResult LegoPathController::FUN_10048310(
} }
} }
if (edgeWithFloat.m_edge != NULL) { if (edgeWithMidpoint.m_edge != NULL) {
pathCtrlEdgeSet.erase(edgeWithFloat.m_edge); pathCtrlEdgeSet.erase(edgeWithMidpoint.m_edge);
boundaryList.push_back(edgeWithFloat); boundaryList.push_back(edgeWithMidpoint);
boundarySet.insert(&boundaryList.back()); boundarySet.insert(&boundaryList.back());
} }
else { else {
@ -920,7 +929,7 @@ MxResult LegoPathController::FUN_10048310(
} }
} }
if (p_grec->GetBit1()) { if (p_grec->HasPath()) {
if (p_grec->size() > 0) { if (p_grec->size() > 0) {
LegoPathCtrlEdge* edge = p_grec->front().m_edge; LegoPathCtrlEdge* edge = p_grec->front().m_edge;
@ -941,8 +950,8 @@ MxResult LegoPathController::FUN_10048310(
} }
} }
if (p_param9 != NULL) { if (p_distance != NULL) {
*p_param9 = local14; *p_distance = minDistance;
} }
return SUCCESS; return SUCCESS;
@ -953,20 +962,20 @@ MxResult LegoPathController::FUN_10048310(
// FUNCTION: LEGO1 0x1004a240 // FUNCTION: LEGO1 0x1004a240
// FUNCTION: BETA10 0x100b9160 // FUNCTION: BETA10 0x100b9160
MxS32 LegoPathController::FUN_1004a240( MxS32 LegoPathController::GetNextPathEdge(
LegoPathEdgeContainer& p_grec, LegoPathEdgeContainer& p_grec,
Vector3& p_v1, Vector3& p_position,
Vector3& p_v2, Vector3& p_direction,
float p_f1, float p_f1,
LegoOrientedEdge*& p_edge, LegoOrientedEdge*& p_edge,
LegoPathBoundary*& p_boundary LegoPathBoundary*& p_boundary
) )
{ {
if (p_grec.size() == 0) { if (p_grec.size() == 0) {
p_v1 = p_grec.m_position; p_position = p_grec.m_position;
p_v2 = p_grec.m_direction; p_direction = p_grec.m_direction;
p_boundary = p_grec.m_boundary; p_boundary = p_grec.m_boundary;
p_grec.SetBit1(FALSE); p_grec.SetPath(FALSE);
return 1; return 1;
} }
@ -975,28 +984,28 @@ MxS32 LegoPathController::FUN_1004a240(
p_grec.pop_front(); p_grec.pop_front();
Mx3DPointFloat vec; Mx3DPointFloat vec;
p_v1 = *p_edge->CCWVertex(*p_boundary); p_position = *p_edge->CCWVertex(*p_boundary);
p_v1 -= *p_edge->CWVertex(*p_boundary); p_position -= *p_edge->CWVertex(*p_boundary);
p_v1 *= p_f1; p_position *= p_f1;
p_v1 += *p_edge->CWVertex(*p_boundary); p_position += *p_edge->CWVertex(*p_boundary);
p_edge->GetFaceNormal(*p_boundary, vec); p_edge->GetFaceNormal(*p_boundary, vec);
p_v2.EqualsCross(*p_boundary->GetUp(), vec); p_direction.EqualsCross(*p_boundary->GetUp(), vec);
return 0; return 0;
} }
// FUNCTION: LEGO1 0x1004a380 // FUNCTION: LEGO1 0x1004a380
// FUNCTION: BETA10 0x100b957f // FUNCTION: BETA10 0x100b957f
MxResult LegoPathController::FUN_1004a380( MxResult LegoPathController::FindIntersectionBoundary(
Vector3& p_param1, Vector3& p_location,
Vector3& p_param2, Vector3& p_direction,
Mx3DPointFloat* p_param3, Mx3DPointFloat* p_coefficients,
LegoPathBoundary*& p_boundary, LegoPathBoundary*& p_boundary,
MxFloat& p_param5 MxFloat& p_apexParameter
) )
{ {
MxFloat param5 = p_param5; MxFloat originalApexParameter = p_apexParameter;
Mx3DPointFloat local24; Mx3DPointFloat intersectionPoint;
MxU32 local8 = TRUE; MxU32 solutionNotFound = TRUE;
for (MxS32 i = 0; i < m_numL; i++) { for (MxS32 i = 0; i < m_numL; i++) {
if (m_boundaries[i].m_flags & LegoPathBoundary::c_bit3) { if (m_boundaries[i].m_flags & LegoPathBoundary::c_bit3) {
@ -1004,75 +1013,76 @@ MxResult LegoPathController::FUN_1004a380(
} }
LegoPathBoundary* b = &m_boundaries[i]; LegoPathBoundary* b = &m_boundaries[i];
Mx4DPointFloat* unk0x14 = b->GetUp(); Mx4DPointFloat* up = b->GetUp();
float local28 = p_param3[0].Dot(p_param3[0], *unk0x14); float coeffADotUp = p_coefficients[0].Dot(p_coefficients[0], *up);
if (local28 < 0.001 && local28 > -0.001) { if (coeffADotUp < 0.001 && coeffADotUp > -0.001) {
continue; continue;
} }
float local2c = p_param3[1].Dot(p_param3[1], *unk0x14); float coeffBDotUp = p_coefficients[1].Dot(p_coefficients[1], *up);
float local34 = p_param3[2].Dot(p_param3[2], *unk0x14) + unk0x14->index_operator(3); float coeffCDotUp = p_coefficients[2].Dot(p_coefficients[2], *up) + up->index_operator(3);
float local3c = local2c * local2c - local34 * local28 * 4.0f; float quadraticDiscriminant = coeffBDotUp * coeffBDotUp - coeffCDotUp * coeffADotUp * 4.0f;
if (local3c < -0.001) { if (quadraticDiscriminant < -0.001) {
continue; continue;
} }
if (local3c < 0.0f) { if (quadraticDiscriminant < 0.0f) {
local3c = 0.0f; quadraticDiscriminant = 0.0f;
} }
else { else {
local3c = sqrt(local3c); quadraticDiscriminant = sqrt(quadraticDiscriminant);
} }
float local38 = (local3c - local2c) / (local28 * 2.0f); float intersectionParameter = (quadraticDiscriminant - coeffBDotUp) / (coeffADotUp * 2.0f);
float local44 = (-local3c - local2c) / (local28 * 2.0f); float alternativeIntersectionParameter = (-quadraticDiscriminant - coeffBDotUp) / (coeffADotUp * 2.0f);
if (!IsBetween(local38, 0.0f, param5)) { if (!IsBetween(intersectionParameter, 0.0f, originalApexParameter)) {
if (IsBetween(local44, 0.0f, param5)) { if (IsBetween(alternativeIntersectionParameter, 0.0f, originalApexParameter)) {
local38 = local44; intersectionParameter = alternativeIntersectionParameter;
} }
else { else {
continue; continue;
} }
} }
if (local8 || FUN_100c17a0(local38, p_param5, 0.0f, param5)) { if (solutionNotFound ||
Mx3DPointFloat local58(p_param3[0]); BothSameComparison(intersectionParameter, p_apexParameter, 0.0f, originalApexParameter)) {
Mx3DPointFloat tSqrA(p_coefficients[0]);
local58 *= local38 * local38; tSqrA *= intersectionParameter * intersectionParameter;
local24 = p_param3[1]; intersectionPoint = p_coefficients[1];
local24 *= local38; intersectionPoint *= intersectionParameter;
local24 += p_param3[2]; intersectionPoint += p_coefficients[2];
local24 += local58; intersectionPoint += tSqrA;
assert(b->GetNumEdges() > 1); assert(b->GetNumEdges() > 1);
MxS32 j; MxS32 j;
for (j = b->GetNumEdges() - 1; j >= 0; j--) { for (j = b->GetNumEdges() - 1; j >= 0; j--) {
Mx4DPointFloat* local60 = b->GetEdgeNormal(j); Mx4DPointFloat* edgeNormal = b->GetEdgeNormal(j);
if (local24.Dot(*local60, local24) + local60->index_operator(3) < -0.001) { if (intersectionPoint.Dot(*edgeNormal, intersectionPoint) + edgeNormal->index_operator(3) < -0.001) {
break; break;
} }
} }
if (j < 0) { if (j < 0) {
Mx3DPointFloat local74(p_param1); Mx3DPointFloat direction(p_location);
local74 -= local24; direction -= intersectionPoint;
if (local74.Dot(local74, *unk0x14) >= 0.0f) { if (direction.Dot(direction, *up) >= 0.0f) {
p_param5 = local38; p_apexParameter = intersectionParameter;
p_boundary = b; p_boundary = b;
local8 = FALSE; solutionNotFound = FALSE;
} }
} }
} }
} }
if (local8) { if (solutionNotFound) {
p_param5 = param5; p_apexParameter = originalApexParameter;
return FAILURE; return FAILURE;
} }

View File

@ -68,7 +68,7 @@ MxBool LegoPathStruct::HandleTrigger(LegoPathActor* p_actor, MxBool p_direction,
case c_h: { case c_h: {
LegoHideAnimPresenter* presenter = m_world->GetHideAnimPresenter(); LegoHideAnimPresenter* presenter = m_world->GetHideAnimPresenter();
if (presenter != NULL) { if (presenter != NULL) {
presenter->FUN_1006db40(p_data * 100); presenter->ApplyVisibility(p_data * 100);
} }
break; break;
} }

View File

@ -119,7 +119,7 @@ void CarRace::ReadyWorld()
{ {
assert(m_hideAnim); assert(m_hideAnim);
LegoWorld::ReadyWorld(); LegoWorld::ReadyWorld();
m_hideAnim->FUN_1006db40(0); m_hideAnim->ApplyVisibility(0);
MxDSAction action; MxDSAction action;
action.SetAtomId(*g_jukeboxScript); action.SetAtomId(*g_jukeboxScript);

View File

@ -83,7 +83,7 @@ void JetskiRace::ReadyWorld()
{ {
assert(m_hideAnim); assert(m_hideAnim);
LegoWorld::ReadyWorld(); LegoWorld::ReadyWorld();
m_hideAnim->FUN_1006db40(0); m_hideAnim->ApplyVisibility(0);
MxDSAction action; MxDSAction action;
action.SetAtomId(*g_jukeboxScript); action.SetAtomId(*g_jukeboxScript);
@ -216,7 +216,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param)
result = 1; result = 1;
} }
else if (m_playerLastPathStruct == 0xf) { else if (m_playerLastPathStruct == 0xf) {
m_hideAnim->FUN_1006db40(m_playerLaps * 200 + 100); m_hideAnim->ApplyVisibility(m_playerLaps * 200 + 100);
result = 1; result = 1;
} }

View File

@ -116,19 +116,19 @@ void LegoRace::Enable(MxBool p_enable)
// FUNCTION: LEGO1 0x10015f30 // FUNCTION: LEGO1 0x10015f30
RaceState::RaceState() RaceState::RaceState()
{ {
m_entries[0].m_id = 1; m_entries[0].m_id = LegoActor::c_pepper;
m_entries[0].m_lastScore = 0; m_entries[0].m_lastScore = 0;
m_entries[0].m_score = 0; m_entries[0].m_score = 0;
m_entries[1].m_id = 2; m_entries[1].m_id = LegoActor::c_mama;
m_entries[1].m_lastScore = 0; m_entries[1].m_lastScore = 0;
m_entries[1].m_score = 0; m_entries[1].m_score = 0;
m_entries[2].m_id = 3; m_entries[2].m_id = LegoActor::c_papa;
m_entries[2].m_lastScore = 0; m_entries[2].m_lastScore = 0;
m_entries[2].m_score = 0; m_entries[2].m_score = 0;
m_entries[3].m_id = 4; m_entries[3].m_id = LegoActor::c_nick;
m_entries[3].m_lastScore = 0; m_entries[3].m_lastScore = 0;
m_entries[3].m_score = 0; m_entries[3].m_score = 0;
m_entries[4].m_id = 5; m_entries[4].m_id = LegoActor::c_laura;
m_entries[4].m_lastScore = 0; m_entries[4].m_lastScore = 0;
m_entries[4].m_score = 0; m_entries[4].m_score = 0;
m_state = RaceState::e_carrace; m_state = RaceState::e_carrace;

View File

@ -25,9 +25,9 @@ LegoRaceActor::LegoRaceActor()
// FUNCTION: LEGO1 0x10014750 // FUNCTION: LEGO1 0x10014750
// FUNCTION: BETA10 0x100c9bba // FUNCTION: BETA10 0x100c9bba
MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) MxS32 LegoRaceActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint)
{ {
MxS32 result = LegoPathActor::VTable0x68(p_v1, p_v2, p_v3); MxS32 result = LegoPathActor::CheckIntersections(p_rayOrigin, p_rayEnd, p_intersectionPoint);
if (m_userNavFlag && result) { if (m_userNavFlag && result) {
MxLong time = Timer()->GetTime(); MxLong time = Timer()->GetTime();
@ -46,20 +46,20 @@ MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3)
// FUNCTION: LEGO1 0x100147f0 // FUNCTION: LEGO1 0x100147f0
// FUNCTION: BETA10 0x100c9c93 // FUNCTION: BETA10 0x100c9c93
MxU32 LegoRaceActor::VTable0x90(float p_time, Matrix4& p_transform) MxU32 LegoRaceActor::StepState(float p_time, Matrix4& p_transform)
{ {
// Note: Code duplication with LegoExtraActor::VTable0x90 // Note: Code duplication with LegoExtraActor::StepState
switch (m_actorState) { switch (m_actorState) {
case c_initial: case c_initial:
case c_one: case c_ready:
return TRUE; return TRUE;
case c_two: case c_hit:
m_unk0x08 = p_time + 2000.0f; m_unk0x08 = p_time + 2000.0f;
m_actorState = c_three; m_actorState = c_hitAnimation;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
return FALSE; return FALSE;
case c_three: case c_hitAnimation:
assert(!m_userNavFlag); assert(!m_userNavFlag);
Vector3 positionRef(p_transform[3]); Vector3 positionRef(p_transform[3]);
@ -73,10 +73,10 @@ MxU32 LegoRaceActor::VTable0x90(float p_time, Matrix4& p_transform)
p_transform.RotateX(0.6); p_transform.RotateX(0.6);
positionRef = position; positionRef = position;
m_actorTime += (p_time - m_lastTime) * m_worldSpeed; m_actorTime += (p_time - m_transformTime) * m_worldSpeed;
m_lastTime = p_time; m_transformTime = p_time;
VTable0x74(p_transform); ApplyTransform(p_transform);
return FALSE; return FALSE;
} }
else { else {
@ -111,7 +111,7 @@ MxResult LegoRaceActor::HitActor(LegoPathActor* p_actor, MxBool p_bool)
roi->SetLocal2World(matr); roi->SetLocal2World(matr);
p_actor->SetActorState(c_two); p_actor->SetActorState(c_hit);
} }
} }

View File

@ -15,7 +15,7 @@ DECOMP_SIZE_ASSERT(LegoRaceMap, 0x1b4)
// FUNCTION: BETA10 0x100ca2c0 // FUNCTION: BETA10 0x100ca2c0
LegoRaceMap::LegoRaceMap() LegoRaceMap::LegoRaceMap()
{ {
m_unk0x08 = FALSE; m_mapEnabled = FALSE;
m_stillPresenter = NULL; m_stillPresenter = NULL;
m_Map_Ctl = 0; m_Map_Ctl = 0;
ControlManager()->Register(this); ControlManager()->Register(this);
@ -54,42 +54,42 @@ void LegoRaceMap::ParseAction(char* p_extra)
if (KeyValueStringParse(value, g_mapGeometry, p_extra)) { if (KeyValueStringParse(value, g_mapGeometry, p_extra)) {
char* token = strtok(value, g_parseExtraTokens); char* token = strtok(value, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x14 = atof(token); m_worldXOffset = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x18 = atof(token); m_worldXScale = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x1c = atof(token); m_worldZOffset = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x20 = atof(token); m_worldZScale = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x24 = atof(token); m_screenXScale = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x28 = atof(token); m_screenYScale = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x2c = atof(token); m_screenXOffset = atof(token);
} }
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
if (token != NULL) { if (token != NULL) {
m_unk0x30 = atof(token); m_screenYOffset = atof(token);
} }
} }
@ -106,13 +106,13 @@ void LegoRaceMap::ParseAction(char* p_extra)
// FUNCTION: LEGO1 0x1005d4b0 // FUNCTION: LEGO1 0x1005d4b0
// FUNCTION: BETA10 0x100ca849 // FUNCTION: BETA10 0x100ca849
void LegoRaceMap::FUN_1005d4b0() void LegoRaceMap::UpdateMapLocatorPosition()
{ {
if (m_unk0x08) { if (m_mapEnabled) {
short xPos = (GetWorldPosition()[0] - m_unk0x14) / m_unk0x18 * m_unk0x24; short xPos = (GetWorldPosition()[0] - m_worldXOffset) / m_worldXScale * m_screenXScale;
short yPos = (GetWorldPosition()[2] - m_unk0x1c) / m_unk0x20 * m_unk0x28; short yPos = (GetWorldPosition()[2] - m_worldZOffset) / m_worldZScale * m_screenYScale;
m_stillPresenter->SetPosition(xPos + m_unk0x2c, m_unk0x30 - yPos); m_stillPresenter->SetPosition(xPos + m_screenXOffset, m_screenYOffset - yPos);
} }
} }
@ -130,12 +130,12 @@ MxLong LegoRaceMap::Notify(MxParam& p_param)
m_Map_Ctl->GetAction()->GetObjectId() == ((LegoControlManagerNotificationParam&) p_param).m_clickedObjectId) { m_Map_Ctl->GetAction()->GetObjectId() == ((LegoControlManagerNotificationParam&) p_param).m_clickedObjectId) {
if (((LegoControlManagerNotificationParam&) p_param).m_enabledChild == 1) { if (((LegoControlManagerNotificationParam&) p_param).m_enabledChild == 1) {
m_unk0x08 = TRUE; m_mapEnabled = TRUE;
FUN_1005d4b0(); UpdateMapLocatorPosition();
m_stillPresenter->Enable(TRUE); m_stillPresenter->Enable(TRUE);
} }
else { else {
m_unk0x08 = FALSE; m_mapEnabled = FALSE;
m_stillPresenter->Enable(FALSE); m_stillPresenter->Enable(FALSE);
} }
} }

View File

@ -174,7 +174,7 @@ MxLong g_timeLastJetskiSoundPlayed = 0;
// FUNCTION: BETA10 0x100cad10 // FUNCTION: BETA10 0x100cad10
LegoRaceCar::LegoRaceCar() LegoRaceCar::LegoRaceCar()
{ {
m_userState = 0; m_kickState = LEGORACECAR_NONE;
m_skelKick1Anim = 0; m_skelKick1Anim = 0;
m_skelKick2Anim = 0; m_skelKick2Anim = 0;
m_unk0x5c.Clear(); m_unk0x5c.Clear();
@ -304,11 +304,11 @@ void LegoRaceCar::KickCamera(float p_param)
LegoAnimActorStruct* a; // called `a` in BETA10 LegoAnimActorStruct* a; // called `a` in BETA10
float deltaTime; float deltaTime;
if (m_userState == LEGORACECAR_KICK1) { if (m_kickState == LEGORACECAR_KICK1) {
a = m_skelKick1Anim; a = m_skelKick1Anim;
} }
else { else {
assert(m_userState == LEGORACECAR_KICK2); assert(m_kickState == LEGORACECAR_KICK2);
a = m_skelKick2Anim; a = m_skelKick2Anim;
} }
@ -318,7 +318,7 @@ void LegoRaceCar::KickCamera(float p_param)
deltaTime = p_param - m_kickStart; deltaTime = p_param - m_kickStart;
if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { if (a->GetDuration() <= deltaTime || deltaTime < 0.0) {
if (m_userState == LEGORACECAR_KICK1) { if (m_kickState == LEGORACECAR_KICK1) {
LegoOrientedEdge** edges = m_kick1B->GetEdges(); LegoOrientedEdge** edges = m_kick1B->GetEdges();
m_destEdge = edges[2]; m_destEdge = edges[2];
m_boundary = m_kick1B; m_boundary = m_kick1B;
@ -329,7 +329,7 @@ void LegoRaceCar::KickCamera(float p_param)
m_boundary = m_kick2B; m_boundary = m_kick2B;
} }
m_userState = LEGORACECAR_UNKNOWN_0; m_kickState = LEGORACECAR_NONE;
} }
else if (a->GetAnimTreePtr()->GetCamAnim()) { else if (a->GetAnimTreePtr()->GetCamAnim()) {
MxMatrix transformationMatrix; MxMatrix transformationMatrix;
@ -373,12 +373,12 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1)
for (MxS32 i = 0; i < sizeOfArray(g_skeletonKickPhases); i++) { for (MxS32 i = 0; i < sizeOfArray(g_skeletonKickPhases); i++) {
if (m_boundary == current->m_edgeRef->m_b && current->m_lower <= skeletonCurAnimPhase && if (m_boundary == current->m_edgeRef->m_b && current->m_lower <= skeletonCurAnimPhase &&
skeletonCurAnimPhase <= current->m_upper) { skeletonCurAnimPhase <= current->m_upper) {
m_userState = current->m_userState; m_kickState = current->m_kickState;
} }
current = &current[1]; current = &current[1];
} }
if (m_userState != LEGORACECAR_KICK1 && m_userState != LEGORACECAR_KICK2) { if (m_kickState != LEGORACECAR_KICK1 && m_kickState != LEGORACECAR_KICK2) {
MxTrace( MxTrace(
// STRING: BETA10 0x101f64c8 // STRING: BETA10 0x101f64c8
"Got kicked in boundary %s %d %g:%g %g\n", "Got kicked in boundary %s %d %g:%g %g\n",
@ -401,21 +401,21 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1)
// FUNCTION: BETA10 0x100cb88a // FUNCTION: BETA10 0x100cb88a
void LegoRaceCar::Animate(float p_time) void LegoRaceCar::Animate(float p_time)
{ {
if (m_userNavFlag && (m_userState == LEGORACECAR_KICK1 || m_userState == LEGORACECAR_KICK2)) { if (m_userNavFlag && (m_kickState == LEGORACECAR_KICK1 || m_kickState == LEGORACECAR_KICK2)) {
KickCamera(p_time); KickCamera(p_time);
return; return;
} }
LegoCarRaceActor::Animate(p_time); LegoCarRaceActor::Animate(p_time);
if (m_userNavFlag && m_userState == LEGORACECAR_UNKNOWN_1) { if (m_userNavFlag && m_kickState == LEGORACECAR_NEAR_SKELETON) {
if (HandleSkeletonKicks(p_time)) { if (HandleSkeletonKicks(p_time)) {
return; return;
} }
} }
if (LegoCarRaceActor::m_animState == 1) { if (LegoCarRaceActor::m_animState == 1) {
FUN_1005d4b0(); UpdateMapLocatorPosition();
if (!m_userNavFlag) { if (!m_userNavFlag) {
FUN_10080590(p_time); FUN_10080590(p_time);
@ -475,7 +475,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool)
Vector3(matr[3]) += g_hitOffset; Vector3(matr[3]) += g_hitOffset;
roi->SetLocal2World(matr); roi->SetLocal2World(matr);
p_actor->SetActorState(c_two); p_actor->SetActorState(c_hit);
} }
if (m_userNavFlag) { if (m_userNavFlag) {
@ -538,36 +538,36 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool)
// FUNCTION: LEGO1 0x10013600 // FUNCTION: LEGO1 0x10013600
// FUNCTION: BETA10 0x100cbe60 // FUNCTION: BETA10 0x100cbe60
MxResult LegoRaceCar::VTable0x9c() MxResult LegoRaceCar::CalculateSpline()
{ {
MxResult result; MxResult result;
if (m_userNavFlag) { if (m_userNavFlag) {
result = LegoCarRaceActor::VTable0x9c(); result = LegoCarRaceActor::CalculateSpline();
if (m_boundary) { if (m_boundary) {
MxS32 bVar2 = 0; MxS32 onSkeletonBoundary = FALSE;
for (MxS32 i = 0; i < sizeOfArray(g_skBMap); i++) { for (MxS32 i = 0; i < sizeOfArray(g_skBMap); i++) {
assert(g_skBMap[i].m_b); assert(g_skBMap[i].m_b);
if (m_boundary == g_skBMap[i].m_b) { if (m_boundary == g_skBMap[i].m_b) {
bVar2 = 1; onSkeletonBoundary = TRUE;
break; break;
} }
} }
if (m_userState == LEGORACECAR_UNKNOWN_1) { if (m_kickState == LEGORACECAR_NEAR_SKELETON) {
if (!bVar2) { if (!onSkeletonBoundary) {
m_userState = LEGORACECAR_UNKNOWN_0; m_kickState = LEGORACECAR_NONE;
} }
} }
else { else {
m_userState = LEGORACECAR_UNKNOWN_1; m_kickState = LEGORACECAR_NEAR_SKELETON;
} }
} }
} }
else { else {
result = LegoCarRaceActor::VTable0x9c(); result = LegoCarRaceActor::CalculateSpline();
} }
return result; return result;
@ -598,7 +598,7 @@ void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed)
// FUNCTION: LEGO1 0x100136f0 // FUNCTION: LEGO1 0x100136f0
// FUNCTION: BETA10 0x100cc01a // FUNCTION: BETA10 0x100cc01a
void LegoJetski::FUN_100136f0(float p_worldSpeed) void LegoJetski::SetMaxLinearVelocity(float p_worldSpeed)
{ {
if (p_worldSpeed < 0) { if (p_worldSpeed < 0) {
LegoCarRaceActor::m_animState = 2; LegoCarRaceActor::m_animState = 2;
@ -617,7 +617,7 @@ void LegoJetski::Animate(float p_time)
LegoJetskiRaceActor::Animate(p_time); LegoJetskiRaceActor::Animate(p_time);
if (LegoCarRaceActor::m_animState == 1) { if (LegoCarRaceActor::m_animState == 1) {
FUN_1005d4b0(); UpdateMapLocatorPosition();
if (!m_userNavFlag) { if (!m_userNavFlag) {
FUN_10080590(p_time); FUN_10080590(p_time);
@ -692,7 +692,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool)
Vector3(matr[3]) += g_hitOffset; Vector3(matr[3]) += g_hitOffset;
roi->SetLocal2World(matr); roi->SetLocal2World(matr);
p_actor->SetActorState(c_two); p_actor->SetActorState(c_hit);
} }
if (m_userNavFlag) { if (m_userNavFlag) {

View File

@ -52,9 +52,9 @@ LegoCarRaceActor::LegoCarRaceActor()
m_unk0x10 = 0.65f; m_unk0x10 = 0.65f;
m_unk0x14 = 0.03f; m_unk0x14 = 0.03f;
m_unk0x18 = 0.6f; m_unk0x18 = 0.6f;
m_unk0x140 = 0.1f; m_wallHitDirectionFactor = 0.1f;
m_unk0x150 = -5.0f; m_linearRotationRatio = -5.0f;
m_unk0x148 = 1; m_canRotate = 1;
VariableTable()->SetVariable(g_fuel, "0.8"); VariableTable()->SetVariable(g_fuel, "0.8");
} }
@ -119,7 +119,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
Mx3DPointFloat destEdgeUnknownVector; Mx3DPointFloat destEdgeUnknownVector;
Mx3DPointFloat crossProduct; Mx3DPointFloat crossProduct;
if (m_actorState == c_one) { if (m_actorState == c_ready) {
m_boundary = NULL; m_boundary = NULL;
// Not sure where the upper bound of 11 comes from, the underlying array has a size of 16 // Not sure where the upper bound of 11 comes from, the underlying array has a size of 16
@ -133,7 +133,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
assert(m_boundary); assert(m_boundary);
m_actorState = c_initial; m_actorState = c_initial;
m_unk0x7c = 0; m_traveledDistance = 0;
if (m_userNavFlag) { if (m_userNavFlag) {
NavController()->SetLinearVel(m_worldSpeed); NavController()->SetLinearVel(m_worldSpeed);
@ -146,7 +146,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
else { else {
for (MxS32 i = 0; i < 11; i += 2) { for (MxS32 i = 0; i < 11; i += 2) {
if (LegoPathController::GetControlEdgeA(i) == p_edge) { if (LegoPathController::GetControlEdgeA(i) == p_edge) {
m_actorState = c_one; m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100f7aec) { if (m_worldSpeed < g_unk0x100f7aec) {
m_worldSpeed = g_unk0x100f7aec; m_worldSpeed = g_unk0x100f7aec;
@ -158,9 +158,9 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
} }
} }
if (m_actorState == c_one) { if (m_actorState == c_ready) {
if (m_userNavFlag) { if (m_userNavFlag) {
m_unk0xe4 = 0.5f; m_destScale = 0.5f;
} }
// variable names verified by BETA10 // variable names verified by BETA10
@ -168,7 +168,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
Vector3* v2 = m_destEdge->CWVertex(*m_boundary); Vector3* v2 = m_destEdge->CWVertex(*m_boundary);
assert(v1 && v2); assert(v1 && v2);
LERP3(pointUnknown, *v1, *v2, m_unk0xe4); LERP3(pointUnknown, *v1, *v2, m_destScale);
m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector); m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector);
@ -185,14 +185,14 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
crossProduct *= 5.0f; crossProduct *= 5.0f;
MxResult callResult = MxResult callResult =
VTable0x80(Vector3(m_roi->GetWorldPosition()), worldDirection, pointUnknown, crossProduct); SetSpline(Vector3(m_roi->GetWorldPosition()), worldDirection, pointUnknown, crossProduct);
if (callResult) { if (callResult) {
m_unk0x7c = 0; m_traveledDistance = 0;
return 0; return 0;
} }
else { else {
m_unk0x7c = 0; m_traveledDistance = 0;
#ifdef BETA10 #ifdef BETA10
assert(0); assert(0);
#endif #endif
@ -217,7 +217,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
// FUNCTION: BETA10 0x100cdb3c // FUNCTION: BETA10 0x100cdb3c
void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4)
{ {
LegoPathActor::SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); LegoPathActor::SwitchBoundary(m_boundary, m_destEdge, m_destScale);
} }
// FUNCTION: LEGO1 0x10080b70 // FUNCTION: LEGO1 0x10080b70
@ -230,7 +230,7 @@ void LegoCarRaceActor::Animate(float p_time)
if (SDL_strcasecmp(value, g_racing) == 0) { if (SDL_strcasecmp(value, g_racing) == 0) {
m_animState = 1; m_animState = 1;
m_lastTime = p_time - 1.0f; m_transformTime = p_time - 1.0f;
m_unk0x1c = p_time; m_unk0x1c = p_time;
} }
} }
@ -242,14 +242,14 @@ void LegoCarRaceActor::Animate(float p_time)
// FUNCTION: LEGO1 0x10080be0 // FUNCTION: LEGO1 0x10080be0
// FUNCTION: BETA10 0x100cdc54 // FUNCTION: BETA10 0x100cdc54
MxResult LegoCarRaceActor::VTable0x9c() MxResult LegoCarRaceActor::CalculateSpline()
{ {
LegoOrientedEdge* d = m_destEdge; LegoOrientedEdge* d = m_destEdge;
if (VTable0x1c(m_boundary, m_destEdge)) { if (VTable0x1c(m_boundary, m_destEdge)) {
LegoPathBoundary* b = m_boundary; LegoPathBoundary* b = m_boundary;
SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); SwitchBoundary(m_boundary, m_destEdge, m_destScale);
assert(m_boundary && m_destEdge); assert(m_boundary && m_destEdge);
// variable names verified by BETA10 // variable names verified by BETA10
@ -258,7 +258,7 @@ MxResult LegoCarRaceActor::VTable0x9c()
assert(v1 && v2); assert(v1 && v2);
Mx3DPointFloat point1; Mx3DPointFloat point1;
LERP3(point1, *v1, *v2, m_unk0xe4); LERP3(point1, *v1, *v2, m_destScale);
Mx3DPointFloat point2; Mx3DPointFloat point2;
Mx3DPointFloat point3; Mx3DPointFloat point3;
@ -277,7 +277,7 @@ MxResult LegoCarRaceActor::VTable0x9c()
point4 *= 5.0f; point4 *= 5.0f;
point5 *= 5.0f; point5 *= 5.0f;
MxResult res = VTable0x80(m_roi->GetWorldPosition(), point4, point1, point5); MxResult res = SetSpline(m_roi->GetWorldPosition(), point4, point1, point5);
#ifdef BETA10 #ifdef BETA10
if (res) { if (res) {
@ -286,7 +286,7 @@ MxResult LegoCarRaceActor::VTable0x9c()
} }
#endif #endif
m_unk0x7c = 0; m_traveledDistance = 0;
} }
return SUCCESS; return SUCCESS;
@ -299,7 +299,7 @@ LegoJetskiRaceActor::LegoJetskiRaceActor()
m_unk0x10 = 0.95f; m_unk0x10 = 0.95f;
m_unk0x14 = 0.04f; m_unk0x14 = 0.04f;
m_unk0x18 = 0.5f; m_unk0x18 = 0.5f;
m_unk0x150 = 1.5f; m_linearRotationRatio = 1.5f;
} }
// FUNCTION: LEGO1 0x10081120 // FUNCTION: LEGO1 0x10081120
@ -315,7 +315,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
Vector3* v1 = NULL; Vector3* v1 = NULL;
Vector3* v2 = NULL; Vector3* v2 = NULL;
if (m_actorState == c_one) { if (m_actorState == c_ready) {
if (m_destEdge == LegoPathController::GetControlEdgeA(13)) { if (m_destEdge == LegoPathController::GetControlEdgeA(13)) {
m_boundary = (LegoPathBoundary*) m_destEdge->OtherFace(LegoPathController::GetControlBoundaryA(13)); m_boundary = (LegoPathBoundary*) m_destEdge->OtherFace(LegoPathController::GetControlBoundaryA(13));
} }
@ -324,7 +324,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
} }
m_actorState = c_initial; m_actorState = c_initial;
m_unk0x7c = 0; m_traveledDistance = 0;
if (m_userNavFlag) { if (m_userNavFlag) {
NavController()->SetLinearVel(m_worldSpeed); NavController()->SetLinearVel(m_worldSpeed);
@ -336,7 +336,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
} }
else { else {
if (p_edge == LegoPathController::GetControlEdgeA(12)) { if (p_edge == LegoPathController::GetControlEdgeA(12)) {
m_actorState = c_one; m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100da044) { if (m_worldSpeed < g_unk0x100da044) {
m_worldSpeed = g_unk0x100da044; m_worldSpeed = g_unk0x100da044;
@ -346,7 +346,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
m_boundary = LegoPathController::GetControlBoundaryA(13); m_boundary = LegoPathController::GetControlBoundaryA(13);
} }
else if (p_edge == LegoPathController::GetControlEdgeA(14)) { else if (p_edge == LegoPathController::GetControlEdgeA(14)) {
m_actorState = c_one; m_actorState = c_ready;
if (m_worldSpeed < g_unk0x100da044) { if (m_worldSpeed < g_unk0x100da044) {
m_worldSpeed = g_unk0x100da044; m_worldSpeed = g_unk0x100da044;
@ -356,16 +356,16 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
m_boundary = LegoPathController::GetControlBoundaryA(15); m_boundary = LegoPathController::GetControlBoundaryA(15);
} }
if (m_actorState == c_one) { if (m_actorState == c_ready) {
if (m_userNavFlag) { if (m_userNavFlag) {
m_unk0xe4 = 0.5f; m_destScale = 0.5f;
} }
v1 = m_destEdge->CCWVertex(*m_boundary); v1 = m_destEdge->CCWVertex(*m_boundary);
v2 = m_destEdge->CWVertex(*m_boundary); v2 = m_destEdge->CWVertex(*m_boundary);
assert(v1 && v2); assert(v1 && v2);
LERP3(a, *v1, *v2, m_unk0xe4); LERP3(a, *v1, *v2, m_destScale);
m_destEdge->GetFaceNormal(*m_boundary, bbb); m_destEdge->GetFaceNormal(*m_boundary, bbb);
c.EqualsCross(bbb, *m_boundary->GetUp()); c.EqualsCross(bbb, *m_boundary->GetUp());
@ -377,9 +377,9 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
worldDirection *= -1.0f; worldDirection *= -1.0f;
} }
if (VTable0x80(m_roi->GetWorldPosition(), worldDirection, a, c)) { if (SetSpline(m_roi->GetWorldPosition(), worldDirection, a, c)) {
#ifndef BETA10 #ifndef BETA10
m_unk0x7c = 0; m_traveledDistance = 0;
return 0; return 0;
#else #else
assert(0); assert(0);
@ -387,7 +387,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
#endif #endif
} }
m_unk0x7c = 0; m_traveledDistance = 0;
return 0; return 0;
} }
else { else {
@ -403,11 +403,11 @@ void LegoJetskiRaceActor::Animate(float p_time)
const LegoChar* raceState = VariableTable()->GetVariable(g_raceState); const LegoChar* raceState = VariableTable()->GetVariable(g_raceState);
if (!SDL_strcasecmp(raceState, g_racing)) { if (!SDL_strcasecmp(raceState, g_racing)) {
m_animState = 1; m_animState = 1;
m_lastTime = p_time - 1.0f; m_transformTime = p_time - 1.0f;
m_unk0x1c = p_time; m_unk0x1c = p_time;
} }
else if (!m_userNavFlag) { else if (!m_userNavFlag) {
LegoAnimActor::Animate(m_lastTime + 1.0f); LegoAnimActor::Animate(m_transformTime + 1.0f);
} }
} }
@ -418,13 +418,13 @@ void LegoJetskiRaceActor::Animate(float p_time)
// FUNCTION: LEGO1 0x10081840 // FUNCTION: LEGO1 0x10081840
// FUNCTION: BETA10 0x100cf680 // FUNCTION: BETA10 0x100cf680
MxU32 LegoCarRaceActor::VTable0x6c( MxU32 LegoCarRaceActor::CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) )
{ {
// STRING: LEGO1 0x100f7af4 // STRING: LEGO1 0x100f7af4
@ -433,7 +433,7 @@ MxU32 LegoCarRaceActor::VTable0x6c(
LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = p_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) {
if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) {
return 1; return 1;
} }
} }
@ -457,8 +457,14 @@ MxU32 LegoCarRaceActor::VTable0x6c(
LegoROI* firstROI = (LegoROI*) co->front(); LegoROI* firstROI = (LegoROI*) co->front();
if (firstROI if (firstROI->Intersect(
->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->GetCollideBox()
)) {
HitActor(actor, TRUE); HitActor(actor, TRUE);
if (actor->HitActor(this, FALSE) < 0) { if (actor->HitActor(this, FALSE) < 0) {
@ -471,8 +477,14 @@ MxU32 LegoCarRaceActor::VTable0x6c(
LegoROI* lastROI = (LegoROI*) co->back(); LegoROI* lastROI = (LegoROI*) co->back();
if (lastROI if (lastROI->Intersect(
->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->GetCollideBox()
)) {
HitActor(actor, TRUE); HitActor(actor, TRUE);
if (actor->HitActor(this, FALSE) < 0) { if (actor->HitActor(this, FALSE) < 0) {
@ -485,7 +497,14 @@ MxU32 LegoCarRaceActor::VTable0x6c(
} }
} }
else { else {
if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { if (roi->Intersect(
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->GetCollideBox()
)) {
HitActor(actor, TRUE); HitActor(actor, TRUE);
if (actor->HitActor(this, FALSE) < 0) { if (actor->HitActor(this, FALSE) < 0) {
@ -505,19 +524,19 @@ MxU32 LegoCarRaceActor::VTable0x6c(
} }
// FUNCTION: LEGO1 0x10081fd0 // FUNCTION: LEGO1 0x10081fd0
MxU32 LegoJetskiRaceActor::VTable0x6c( MxU32 LegoJetskiRaceActor::CheckPresenterAndActorIntersections(
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
Vector3& p_v1, Vector3& p_rayOrigin,
Vector3& p_v2, Vector3& p_rayDirection,
float p_f1, float p_rayLength,
float p_f2, float p_radius,
Vector3& p_v3 Vector3& p_intersectionPoint
) )
{ {
LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); LegoAnimPresenterSet& presenters = p_boundary->GetPresenters();
for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) {
if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) {
return 1; return 1;
} }
} }
@ -533,7 +552,14 @@ MxU32 LegoJetskiRaceActor::VTable0x6c(
LegoROI* roi = actor->GetROI(); LegoROI* roi = actor->GetROI();
if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) { if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) {
if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { if (roi->Intersect(
p_rayOrigin,
p_rayDirection,
p_rayLength,
p_radius,
p_intersectionPoint,
m_collideBox && actor->GetCollideBox()
)) {
HitActor(actor, TRUE); HitActor(actor, TRUE);
if (actor->HitActor(this, FALSE) < 0) { if (actor->HitActor(this, FALSE) < 0) {

View File

@ -57,21 +57,21 @@ void LegoAnimPresenter::Init()
m_roiMapSize = 0; m_roiMapSize = 0;
m_managedActors = NULL; m_managedActors = NULL;
m_sceneROIs = NULL; m_sceneROIs = NULL;
m_unk0x78 = NULL; m_transform = NULL;
m_flags = 0; m_flags = 0;
m_unk0xa8.Clear(); m_centerPoint.Clear();
m_unk0xa4 = 0; m_boundingRadius = 0;
m_currentWorld = NULL; m_currentWorld = NULL;
m_unk0x95 = FALSE; m_animationFinished = FALSE;
m_worldId = -1; m_worldId = -1;
m_substMap = NULL; m_substMap = NULL;
m_worldAtom.Clear(); m_worldAtom.Clear();
m_unk0x9c = 0; m_roiTransformApplied = 0;
m_unk0x8c = NULL; m_ptAtCamROI = NULL;
m_unk0x90 = NULL; m_ptAtCamNames = NULL;
m_unk0x94 = 0; m_ptAtCamCount = 0;
m_unk0x96 = TRUE; m_localActors = TRUE;
m_unk0xa0 = NULL; m_roiTransform = NULL;
} }
// FUNCTION: LEGO1 0x10068770 // FUNCTION: LEGO1 0x10068770
@ -94,12 +94,12 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor)
} }
if (m_managedActors != NULL) { if (m_managedActors != NULL) {
FUN_1006aa60(); ReleaseManagedActors();
delete m_managedActors; delete m_managedActors;
} }
if (m_unk0x78 != NULL) { if (m_transform != NULL) {
delete m_unk0x78; delete m_transform;
} }
if (m_substMap != NULL) { if (m_substMap != NULL) {
@ -115,22 +115,22 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor)
delete m_substMap; delete m_substMap;
} }
if (m_unk0x90 != NULL) { if (m_ptAtCamNames != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) { for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
if (m_unk0x90[i] != NULL) { if (m_ptAtCamNames[i] != NULL) {
delete[] m_unk0x90[i]; delete[] m_ptAtCamNames[i];
} }
} }
delete[] m_unk0x90; delete[] m_ptAtCamNames;
} }
if (m_unk0x8c != NULL) { if (m_ptAtCamROI != NULL) {
delete[] m_unk0x8c; delete[] m_ptAtCamROI;
} }
if (m_unk0xa0 != NULL) { if (m_roiTransform != NULL) {
delete m_unk0xa0; delete m_roiTransform;
} }
Init(); Init();
@ -153,16 +153,16 @@ MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk)
if (storage.Read(&magicSig, sizeof(MxS32)) != SUCCESS || magicSig != 0x11) { if (storage.Read(&magicSig, sizeof(MxS32)) != SUCCESS || magicSig != 0x11) {
goto done; goto done;
} }
if (storage.Read(&m_unk0xa4, sizeof(float)) != SUCCESS) { if (storage.Read(&m_boundingRadius, sizeof(float)) != SUCCESS) {
goto done; goto done;
} }
if (storage.Read(&m_unk0xa8[0], sizeof(float)) != SUCCESS) { if (storage.Read(&m_centerPoint[0], sizeof(float)) != SUCCESS) {
goto done; goto done;
} }
if (storage.Read(&m_unk0xa8[1], sizeof(float)) != SUCCESS) { if (storage.Read(&m_centerPoint[1], sizeof(float)) != SUCCESS) {
goto done; goto done;
} }
if (storage.Read(&m_unk0xa8[2], sizeof(float)) != SUCCESS) { if (storage.Read(&m_centerPoint[2], sizeof(float)) != SUCCESS) {
goto done; goto done;
} }
if (storage.Read(&parseScene, sizeof(LegoS32)) != SUCCESS) { if (storage.Read(&parseScene, sizeof(LegoS32)) != SUCCESS) {
@ -193,24 +193,24 @@ MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk)
} }
// FUNCTION: LEGO1 0x10069150 // FUNCTION: LEGO1 0x10069150
LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) LegoChar* LegoAnimPresenter::GetActorName(const LegoChar* p_name)
{ {
LegoChar* str; LegoChar* str;
if (LegoCharacterManager::IsActor(p_und1 + 1)) { if (LegoCharacterManager::IsActor(p_name + 1)) {
str = new LegoChar[strlen(p_und1)]; str = new LegoChar[strlen(p_name)];
if (str != NULL) { if (str != NULL) {
strcpy(str, p_und1 + 1); strcpy(str, p_name + 1);
} }
} }
else { else {
LegoChar buffer[32]; LegoChar buffer[32];
sprintf(buffer, "%d", m_action->GetUnknown24()); sprintf(buffer, "%d", m_action->GetUnknown24());
str = new LegoChar[strlen(p_und1) + strlen(buffer) + strlen(GetActionObjectName()) + 1]; str = new LegoChar[strlen(p_name) + strlen(buffer) + strlen(GetActionObjectName()) + 1];
if (str != NULL) { if (str != NULL) {
strcpy(str, p_und1); strcpy(str, p_name);
strcat(str, buffer); strcat(str, buffer);
strcat(str, GetActionObjectName()); strcat(str, GetActionObjectName());
} }
@ -220,7 +220,7 @@ LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1)
} }
// FUNCTION: LEGO1 0x100692b0 // FUNCTION: LEGO1 0x100692b0
void LegoAnimPresenter::FUN_100692b0() void LegoAnimPresenter::CreateManagedActors()
{ {
m_managedActors = new LegoROIList(); m_managedActors = new LegoROIList();
@ -232,7 +232,7 @@ void LegoAnimPresenter::FUN_100692b0()
LegoU32 actorType = m_anim->GetActorType(i); LegoU32 actorType = m_anim->GetActorType(i);
LegoROI* roi = NULL; LegoROI* roi = NULL;
if (actorType == LegoAnimActorEntry::e_actorType2) { if (actorType == LegoAnimActorEntry::e_managedLegoActor) {
LegoChar* src; LegoChar* src;
if (str[0] == '*') { if (str[0] == '*') {
src = str + 1; src = str + 1;
@ -247,44 +247,44 @@ void LegoAnimPresenter::FUN_100692b0()
roi->SetVisibility(FALSE); roi->SetVisibility(FALSE);
} }
} }
else if (actorType == LegoAnimActorEntry::e_actorType4) { else if (actorType == LegoAnimActorEntry::e_managedInvisibleRoi) {
LegoChar* baseName = new LegoChar[strlen(str)]; LegoChar* baseName = new LegoChar[strlen(str)];
strcpy(baseName, str + 1); strcpy(baseName, str + 1);
SDL_strlwr(baseName); SDL_strlwr(baseName);
LegoChar* und = FUN_10069150(str); LegoChar* roiName = GetActorName(str);
roi = CharacterManager()->FUN_10085a80(und, baseName, TRUE); roi = CharacterManager()->FUN_10085a80(roiName, baseName, TRUE);
if (roi != NULL) { if (roi != NULL) {
roi->SetVisibility(FALSE); roi->SetVisibility(FALSE);
} }
delete[] baseName; delete[] baseName;
delete[] und; delete[] roiName;
} }
else if (actorType == LegoAnimActorEntry::e_actorType3) { else if (actorType == LegoAnimActorEntry::e_managedInvisibleRoiTrimmed) {
LegoChar* lodName = new LegoChar[strlen(str)]; LegoChar* lodName = new LegoChar[strlen(str)];
strcpy(lodName, str + 1); strcpy(lodName, str + 1);
for (LegoChar* i = &lodName[strlen(lodName) - 1]; i > lodName; i--) { for (LegoChar* c = &lodName[strlen(lodName) - 1]; c > lodName; c--) {
if ((*i < '0' || *i > '9') && *i != '_') { if ((*c < '0' || *c > '9') && *c != '_') {
break; break;
} }
*i = '\0'; *c = '\0';
} }
SDL_strlwr(lodName); SDL_strlwr(lodName);
LegoChar* und = FUN_10069150(str); LegoChar* roiName = GetActorName(str);
roi = CharacterManager()->CreateAutoROI(und, lodName, TRUE); roi = CharacterManager()->CreateAutoROI(roiName, lodName, TRUE);
if (roi != NULL) { if (roi != NULL) {
roi->SetVisibility(FALSE); roi->SetVisibility(FALSE);
} }
delete[] lodName; delete[] lodName;
delete[] und; delete[] roiName;
} }
if (roi != NULL) { if (roi != NULL) {
@ -298,7 +298,7 @@ void LegoAnimPresenter::FUN_100692b0()
// FUNCTION: LEGO1 0x100695c0 // FUNCTION: LEGO1 0x100695c0
// FUNCTION: BETA10 0x1004f359 // FUNCTION: BETA10 0x1004f359
void LegoAnimPresenter::FUN_100695c0() void LegoAnimPresenter::CreateSceneROIs()
{ {
m_sceneROIs = new LegoROIList(); m_sceneROIs = new LegoROIList();
@ -307,10 +307,10 @@ void LegoAnimPresenter::FUN_100695c0()
LegoU32 numActors = m_anim->GetNumActors(); LegoU32 numActors = m_anim->GetNumActors();
for (LegoU32 i = 0; i < numActors; i++) { for (LegoU32 i = 0; i < numActors; i++) {
if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { if (AppendROIToScene(rois, m_anim->GetActorName(i)) == FALSE) {
LegoU32 actorType = m_anim->GetActorType(i); LegoU32 actorType = m_anim->GetActorType(i);
if (actorType == LegoAnimActorEntry::e_actorType5 || actorType == LegoAnimActorEntry::e_actorType6) { if (actorType == LegoAnimActorEntry::e_sceneRoi1 || actorType == LegoAnimActorEntry::e_sceneRoi2) {
LegoChar lodName[256]; LegoChar lodName[256];
const LegoChar* actorName = m_anim->GetActorName(i); const LegoChar* actorName = m_anim->GetActorName(i);
@ -324,7 +324,7 @@ void LegoAnimPresenter::FUN_100695c0()
SDL_strlwr(lodName); SDL_strlwr(lodName);
CharacterManager()->CreateAutoROI(actorName, lodName, FALSE); CharacterManager()->CreateAutoROI(actorName, lodName, FALSE);
FUN_100698b0(rois, actorName); AppendROIToScene(rois, actorName);
} }
} }
} }
@ -359,13 +359,13 @@ LegoChar* LegoAnimPresenter::GetVariableOrIdentity(const LegoChar* p_varName, co
} }
// FUNCTION: LEGO1 0x100698b0 // FUNCTION: LEGO1 0x100698b0
LegoBool LegoAnimPresenter::FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2) LegoBool LegoAnimPresenter::AppendROIToScene(const CompoundObject& p_rois, const LegoChar* p_varName)
{ {
LegoBool result = FALSE; LegoBool result = FALSE;
LegoChar* str; LegoChar* str;
if (*(str = GetVariableOrIdentity(p_und2, NULL)) == '*') { if (*(str = GetVariableOrIdentity(p_varName, NULL)) == '*') {
LegoChar* tmp = FUN_10069150(str); LegoChar* tmp = GetActorName(str);
delete[] str; delete[] str;
str = tmp; str = tmp;
} }
@ -410,12 +410,12 @@ LegoROI* LegoAnimPresenter::FindROI(const LegoChar* p_name)
} }
// FUNCTION: LEGO1 0x10069b10 // FUNCTION: LEGO1 0x10069b10
void LegoAnimPresenter::FUN_10069b10() void LegoAnimPresenter::BuildROIMap()
{ {
LegoAnimStructMap anims; LegoAnimStructMap anims;
if (m_unk0x8c != NULL) { if (m_ptAtCamROI != NULL) {
memset(m_unk0x8c, 0, m_unk0x94 * sizeof(*m_unk0x8c)); memset(m_ptAtCamROI, 0, m_ptAtCamCount * sizeof(*m_ptAtCamROI));
} }
UpdateStructMapAndROIIndex(anims, m_anim->GetRoot(), NULL); UpdateStructMapAndROIIndex(anims, m_anim->GetRoot(), NULL);
@ -434,10 +434,10 @@ void LegoAnimPresenter::FUN_10069b10()
m_roiMap[index] = (*it).second.m_roi; m_roiMap[index] = (*it).second.m_roi;
if (m_roiMap[index]->GetName() != NULL) { if (m_roiMap[index]->GetName() != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) { for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
if (m_unk0x8c[i] == NULL && m_unk0x90[i] != NULL) { if (m_ptAtCamROI[i] == NULL && m_ptAtCamNames[i] != NULL) {
if (!SDL_strcasecmp(m_unk0x90[i], m_roiMap[index]->GetName())) { if (!SDL_strcasecmp(m_ptAtCamNames[i], m_roiMap[index]->GetName())) {
m_unk0x8c[i] = m_roiMap[index]; m_ptAtCamROI[i] = m_roiMap[index];
break; break;
} }
} }
@ -461,7 +461,7 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, Leg
if (name != NULL && *name != '-') { if (name != NULL && *name != '-') {
if (*name == '*') { if (*name == '*') {
name = und2 = FUN_10069150(name); name = und2 = GetActorName(name);
} }
und = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL); und = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL);
@ -506,13 +506,13 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, Leg
void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode( void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode(
LegoAnimStructMap& p_map, LegoAnimStructMap& p_map,
LegoAnimNodeData* p_data, LegoAnimNodeData* p_data,
const LegoChar* p_und, const LegoChar* p_key,
LegoROI* p_roi LegoROI* p_roi
) )
{ {
LegoAnimStructMap::iterator it; LegoAnimStructMap::iterator it;
it = p_map.find(p_und); it = p_map.find(p_key);
if (it == p_map.end()) { if (it == p_map.end()) {
LegoAnimStruct animStruct; LegoAnimStruct animStruct;
animStruct.m_index = p_map.size() + 1; animStruct.m_index = p_map.size() + 1;
@ -520,10 +520,10 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode(
p_data->SetROIIndex(animStruct.m_index); p_data->SetROIIndex(animStruct.m_index);
LegoChar* und = new LegoChar[strlen(p_und) + 1]; LegoChar* key = new LegoChar[strlen(p_key) + 1];
strcpy(und, p_und); strcpy(key, p_key);
p_map[und] = animStruct; p_map[key] = animStruct;
} }
else { else {
p_data->SetROIIndex((*it).second.m_index); p_data->SetROIIndex((*it).second.m_index);
@ -532,7 +532,7 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode(
// FUNCTION: LEGO1 0x1006aa60 // FUNCTION: LEGO1 0x1006aa60
// FUNCTION: BETA10 0x1004feee // FUNCTION: BETA10 0x1004feee
void LegoAnimPresenter::FUN_1006aa60() void LegoAnimPresenter::ReleaseManagedActors()
{ {
LegoROIListCursor cursor(m_managedActors); LegoROIListCursor cursor(m_managedActors);
LegoROI* roi; LegoROI* roi;
@ -540,16 +540,16 @@ void LegoAnimPresenter::FUN_1006aa60()
while (cursor.Next(roi)) { while (cursor.Next(roi)) {
const char* name = roi->GetName(); const char* name = roi->GetName();
if (m_unk0x96 || !CharacterManager()->IsActor(name)) { if (m_localActors || !CharacterManager()->IsActor(name)) {
CharacterManager()->ReleaseActor(name); CharacterManager()->ReleaseActor(name);
} }
} }
} }
// FUNCTION: LEGO1 0x1006ab70 // FUNCTION: LEGO1 0x1006ab70
void LegoAnimPresenter::FUN_1006ab70() void LegoAnimPresenter::AppendManagedActors()
{ {
if (m_unk0x96) { if (m_localActors) {
AnimationManager()->FUN_10063270(m_managedActors, this); AnimationManager()->FUN_10063270(m_managedActors, this);
} }
else { else {
@ -558,25 +558,25 @@ void LegoAnimPresenter::FUN_1006ab70()
} }
// FUNCTION: LEGO1 0x1006aba0 // FUNCTION: LEGO1 0x1006aba0
LegoBool LegoAnimPresenter::FUN_1006aba0() LegoBool LegoAnimPresenter::VerifyAnimationTree()
{ {
return FUN_1006abb0(m_anim->GetRoot(), 0); return VerifyAnimationNode(m_anim->GetRoot(), NULL);
} }
// FUNCTION: LEGO1 0x1006abb0 // FUNCTION: LEGO1 0x1006abb0
MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) MxBool LegoAnimPresenter::VerifyAnimationNode(LegoTreeNode* p_node, LegoROI* p_roi)
{ {
MxBool result = FALSE; MxBool result = FALSE;
LegoROI* roi = p_roi; LegoROI* roi = p_roi;
LegoChar* und = NULL; LegoChar* varOrName = NULL;
const LegoChar* name = ((LegoAnimNodeData*) p_node->GetData())->GetName(); const LegoChar* name = ((LegoAnimNodeData*) p_node->GetData())->GetName();
MxS32 i, count; MxS32 i, count;
if (name != NULL && *name != '-') { if (name != NULL && *name != '-') {
und = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL); varOrName = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL);
if (p_roi == NULL) { if (p_roi == NULL) {
roi = FindROI(und); roi = FindROI(varOrName);
if (roi == NULL) { if (roi == NULL) {
goto done; goto done;
@ -587,7 +587,7 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi)
if (child == NULL) { if (child == NULL) {
if (FindROI(name) != NULL) { if (FindROI(name) != NULL) {
if (FUN_1006abb0(p_node, NULL)) { if (VerifyAnimationNode(p_node, NULL)) {
result = TRUE; result = TRUE;
} }
} }
@ -599,7 +599,7 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi)
count = p_node->GetNumChildren(); count = p_node->GetNumChildren();
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (!FUN_1006abb0(p_node->GetChild(i), roi)) { if (!VerifyAnimationNode(p_node->GetChild(i), roi)) {
goto done; goto done;
} }
} }
@ -607,8 +607,8 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi)
result = TRUE; result = TRUE;
done: done:
if (und != NULL) { if (varOrName != NULL) {
delete[] und; delete[] varOrName;
} }
return result; return result;
@ -640,12 +640,12 @@ void LegoAnimPresenter::PutFrame()
time = 0; time = 0;
} }
FUN_1006b9a0(m_anim, time, m_unk0x78); ApplyTransformWithVisibilityAndCam(m_anim, time, m_transform);
if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { if (m_ptAtCamROI != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) { for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
if (m_unk0x8c[i] != NULL) { if (m_ptAtCamROI[i] != NULL) {
MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); MxMatrix mat(m_ptAtCamROI[i]->GetLocal2World());
Vector3 pos(mat[0]); Vector3 pos(mat[0]);
Vector3 dir(mat[1]); Vector3 dir(mat[1]);
@ -667,8 +667,8 @@ void LegoAnimPresenter::PutFrame()
dir *= dirsqr; dir *= dirsqr;
up *= upsqr; up *= upsqr;
m_unk0x8c[i]->SetLocal2World(mat); m_ptAtCamROI[i]->SetLocal2World(mat);
m_unk0x8c[i]->WrappedUpdateWorldData(); m_ptAtCamROI[i]->WrappedUpdateWorldData();
} }
} }
} }
@ -677,7 +677,7 @@ void LegoAnimPresenter::PutFrame()
// FUNCTION: LEGO1 0x1006afc0 // FUNCTION: LEGO1 0x1006afc0
// FUNCTION: BETA10 0x1005059a // FUNCTION: BETA10 0x1005059a
MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und) MxResult LegoAnimPresenter::GetTransforms(MxMatrix*& p_matrix, float p_time)
{ {
MxU32 length = m_roiMapSize + 1; MxU32 length = m_roiMapSize + 1;
p_matrix = new MxMatrix[length]; p_matrix = new MxMatrix[length];
@ -689,7 +689,7 @@ MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und)
} }
} }
FUN_1006b900(m_anim, p_und, m_unk0x78); ApplyTransform(m_anim, p_time, m_transform);
for (i = 1; i < length; i++) { for (i = 1; i < length; i++) {
MxMatrix mat; MxMatrix mat;
@ -706,7 +706,7 @@ MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und)
// FUNCTION: LEGO1 0x1006b140 // FUNCTION: LEGO1 0x1006b140
// FUNCTION: BETA10 0x100507e0 // FUNCTION: BETA10 0x100507e0
MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) MxResult LegoAnimPresenter::CopyTransform(LegoROI* p_roi)
{ {
if (p_roi == NULL) { if (p_roi == NULL) {
return FAILURE; return FAILURE;
@ -720,16 +720,16 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi)
MxMatrix inverse; MxMatrix inverse;
const Matrix4& local2world = p_roi->GetLocal2World(); const Matrix4& local2world = p_roi->GetLocal2World();
MxMatrix* local5c; MxMatrix* roiTransforms;
MxU32 i; MxU32 i;
if (FUN_1006afc0(local5c, 0.0f) != SUCCESS) { if (GetTransforms(roiTransforms, 0.0f) != SUCCESS) {
goto done; goto done;
} }
for (i = 1; i <= m_roiMapSize; i++) { for (i = 1; i <= m_roiMapSize; i++) {
if (m_roiMap[i] == p_roi) { if (m_roiMap[i] == p_roi) {
if (local5c[i].Invert(inverse) != SUCCESS) { if (roiTransforms[i].Invert(inverse) != SUCCESS) {
goto done; goto done;
} }
@ -739,15 +739,15 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi)
{ {
mn->Product(inverse, local2world); mn->Product(inverse, local2world);
SetUnknown0xa0(mn); SetRoiTransform(mn);
delete[] local5c; delete[] roiTransforms;
SetUnknown0x0cTo1(); SetRoiTransformApplied();
MxMatrix local140(*m_unk0x78); MxMatrix originalTransform(*m_transform);
MxMatrix localf8; MxMatrix newTransform;
localf8.Product(local140, *m_unk0xa0); newTransform.Product(originalTransform, *m_roiTransform);
*m_unk0x78 = localf8; *m_transform = newTransform;
return SUCCESS; return SUCCESS;
} }
@ -756,8 +756,8 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi)
delete mn; delete mn;
} }
if (local5c != NULL) { if (roiTransforms != NULL) {
delete[] local5c; delete[] roiTransforms;
} }
return FAILURE; return FAILURE;
@ -793,22 +793,22 @@ void LegoAnimPresenter::ReadyTickle()
void LegoAnimPresenter::StartingTickle() void LegoAnimPresenter::StartingTickle()
{ {
SubstituteVariables(); SubstituteVariables();
FUN_100692b0(); CreateManagedActors();
FUN_100695c0(); CreateSceneROIs();
if (m_flags & c_mustSucceed && !FUN_1006aba0()) { if (m_flags & c_mustSucceed && !VerifyAnimationTree()) {
goto done; goto done;
} }
FUN_10069b10(); BuildROIMap();
SetDisabled(TRUE); SetDisabled(TRUE);
if (m_unk0x78 == NULL) { if (m_transform == NULL) {
if (fabs(m_action->GetDirection()[0]) >= 0.00000047683716F || if (fabs(m_action->GetDirection()[0]) >= 0.00000047683716F ||
fabs(m_action->GetDirection()[1]) >= 0.00000047683716F || fabs(m_action->GetDirection()[1]) >= 0.00000047683716F ||
fabs(m_action->GetDirection()[2]) >= 0.00000047683716F) { fabs(m_action->GetDirection()[2]) >= 0.00000047683716F) {
m_unk0x78 = new MxMatrix(); m_transform = new MxMatrix();
CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_unk0x78); CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_transform);
} }
else if (m_roiMap != NULL) { else if (m_roiMap != NULL) {
LegoROI* roi = m_roiMap[1]; LegoROI* roi = m_roiMap[1];
@ -816,14 +816,14 @@ void LegoAnimPresenter::StartingTickle()
if (roi != NULL) { if (roi != NULL) {
MxMatrix mat; MxMatrix mat;
mat = roi->GetLocal2World(); mat = roi->GetLocal2World();
m_unk0x78 = new MxMatrix(mat); m_transform = new MxMatrix(mat);
} }
} }
} }
if ((m_action->GetDuration() == -1 || ((MxDSMediaAction*) m_action)->GetSustainTime() == -1) && if ((m_action->GetDuration() == -1 || ((MxDSMediaAction*) m_action)->GetSustainTime() == -1) &&
m_compositePresenter) { m_compositePresenter) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
else { else {
m_action->SetTimeStarted(Timer()->GetTime()); m_action->SetTimeStarted(Timer()->GetTime());
@ -832,11 +832,11 @@ void LegoAnimPresenter::StartingTickle()
ProgressTickleState(e_streaming); ProgressTickleState(e_streaming);
if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) { if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) {
m_unk0x96 = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); m_localActors = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0();
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
VTable0x8c(); AddToWorld();
done: done:
if (m_sceneROIs != NULL) { if (m_sceneROIs != NULL) {
@ -853,17 +853,17 @@ void LegoAnimPresenter::StreamingTickle()
m_subscriber->FreeDataChunk(chunk); m_subscriber->FreeDataChunk(chunk);
} }
if (m_unk0x95) { if (m_animationFinished) {
ProgressTickleState(e_done); ProgressTickleState(e_done);
if (m_compositePresenter) { if (m_compositePresenter) {
if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
} }
} }
else { else {
if (m_action->GetElapsedTime() > m_anim->GetDuration() + m_action->GetStartTime()) { if (m_action->GetElapsedTime() > m_anim->GetDuration() + m_action->GetStartTime()) {
m_unk0x95 = TRUE; m_animationFinished = TRUE;
} }
} }
} }
@ -894,7 +894,7 @@ const char* LegoAnimPresenter::GetActionObjectName()
// FUNCTION: LEGO1 0x1006b900 // FUNCTION: LEGO1 0x1006b900
// FUNCTION: BETA10 0x100510d8 // FUNCTION: BETA10 0x100510d8
void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) void LegoAnimPresenter::ApplyTransform(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix)
{ {
LegoTreeNode* root = p_anim->GetRoot(); LegoTreeNode* root = p_anim->GetRoot();
MxMatrix mat; MxMatrix mat;
@ -919,7 +919,7 @@ void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p
// FUNCTION: LEGO1 0x1006b9a0 // FUNCTION: LEGO1 0x1006b9a0
// FUNCTION: BETA10 0x1005118b // FUNCTION: BETA10 0x1005118b
void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) void LegoAnimPresenter::ApplyTransformWithVisibilityAndCam(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix)
{ {
LegoTreeNode* root = p_anim->GetRoot(); LegoTreeNode* root = p_anim->GetRoot();
MxMatrix mat; MxMatrix mat;
@ -1010,43 +1010,43 @@ void LegoAnimPresenter::ParseExtra()
} }
if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) { if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) {
list<char*> tmp; list<char*> tokens;
if (m_unk0x90 != NULL) { if (m_ptAtCamNames != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) { for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
if (m_unk0x90[i] != NULL) { if (m_ptAtCamNames[i] != NULL) {
// (modernization) critical bug: wrong free // (modernization) critical bug: wrong free
delete[] m_unk0x90; delete[] m_ptAtCamNames;
} }
} }
delete[] m_unk0x90; delete[] m_ptAtCamNames;
m_unk0x90 = NULL; m_ptAtCamNames = NULL;
} }
if (m_unk0x8c != NULL) { if (m_ptAtCamROI != NULL) {
delete[] m_unk0x8c; delete[] m_ptAtCamROI;
m_unk0x8c = NULL; m_ptAtCamROI = NULL;
} }
char* token = strtok(output, g_parseExtraTokens); char* token = strtok(output, g_parseExtraTokens);
while (token != NULL) { while (token != NULL) {
char* valueCopy = new char[strlen(token) + 1]; char* valueCopy = new char[strlen(token) + 1];
strcpy(valueCopy, token); strcpy(valueCopy, token);
tmp.push_back(valueCopy); tokens.push_back(valueCopy);
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);
} }
m_unk0x94 = tmp.size(); m_ptAtCamCount = tokens.size();
if (m_unk0x94 != 0) { if (m_ptAtCamCount != 0) {
m_unk0x8c = new LegoROI*[m_unk0x94]; m_ptAtCamROI = new LegoROI*[m_ptAtCamCount];
m_unk0x90 = new char*[m_unk0x94]; m_ptAtCamNames = new char*[m_ptAtCamCount];
memset(m_unk0x8c, 0, sizeof(*m_unk0x8c) * m_unk0x94); memset(m_ptAtCamROI, 0, sizeof(*m_ptAtCamROI) * m_ptAtCamCount);
memset(m_unk0x90, 0, sizeof(*m_unk0x90) * m_unk0x94); memset(m_ptAtCamNames, 0, sizeof(*m_ptAtCamNames) * m_ptAtCamCount);
MxS32 i = 0; MxS32 i = 0;
for (list<char*>::iterator it = tmp.begin(); it != tmp.end(); it++, i++) { for (list<char*>::iterator it = tokens.begin(); it != tokens.end(); it++, i++) {
m_unk0x90[i] = *it; m_ptAtCamNames[i] = *it;
} }
} }
} }
@ -1055,13 +1055,13 @@ void LegoAnimPresenter::ParseExtra()
// FUNCTION: LEGO1 0x1006c570 // FUNCTION: LEGO1 0x1006c570
// FUNCTION: BETA10 0x10051ab3 // FUNCTION: BETA10 0x10051ab3
void LegoAnimPresenter::VTable0xa0(Matrix4& p_matrix) void LegoAnimPresenter::SetTransform(Matrix4& p_matrix)
{ {
if (m_unk0x78 != NULL) { if (m_transform != NULL) {
delete m_unk0x78; delete m_transform;
} }
m_unk0x78 = new MxMatrix(p_matrix); m_transform = new MxMatrix(p_matrix);
} }
// FUNCTION: LEGO1 0x1006c620 // FUNCTION: LEGO1 0x1006c620
@ -1090,7 +1090,7 @@ void LegoAnimPresenter::EndAction()
} }
if (m_anim != NULL) { if (m_anim != NULL) {
FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); ApplyTransformWithVisibilityAndCam(m_anim, m_anim->GetDuration(), m_transform);
} }
if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) { if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) {
@ -1102,8 +1102,8 @@ void LegoAnimPresenter::EndAction()
} }
SetDisabled(FALSE); SetDisabled(FALSE);
FUN_1006ab70(); AppendManagedActors();
VTable0x90(); RemoveFromWorld();
if (m_currentWorld != NULL) { if (m_currentWorld != NULL) {
m_currentWorld->Remove(this); m_currentWorld->Remove(this);
@ -1114,24 +1114,24 @@ void LegoAnimPresenter::EndAction()
// FUNCTION: LEGO1 0x1006c7a0 // FUNCTION: LEGO1 0x1006c7a0
// FUNCTION: BETA10 0x10051da6 // FUNCTION: BETA10 0x10051da6
void LegoAnimPresenter::FUN_1006c7a0() void LegoAnimPresenter::ApplyFinishedTransform()
{ {
if (m_anim != NULL) { if (m_anim != NULL) {
FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); ApplyTransformWithVisibilityAndCam(m_anim, m_anim->GetDuration(), m_transform);
} }
m_unk0x95 = TRUE; m_animationFinished = TRUE;
} }
// FUNCTION: LEGO1 0x1006c7d0 // FUNCTION: LEGO1 0x1006c7d0
// FUNCTION: BETA10 0x10051e07 // FUNCTION: BETA10 0x10051e07
void LegoAnimPresenter::VTable0x8c() void LegoAnimPresenter::AddToWorld()
{ {
if (m_unk0x78) { if (m_transform) {
m_unk0xa8 += (*m_unk0x78)[3]; m_centerPoint += (*m_transform)[3];
} }
else { else {
m_unk0xa8 += m_action->GetLocation(); m_centerPoint += m_action->GetLocation();
} }
if (m_currentWorld == NULL) { if (m_currentWorld == NULL) {
@ -1148,7 +1148,7 @@ void LegoAnimPresenter::VTable0x8c()
// FUNCTION: LEGO1 0x1006c860 // FUNCTION: LEGO1 0x1006c860
// FUNCTION: BETA10 0x10051f45 // FUNCTION: BETA10 0x10051f45
void LegoAnimPresenter::VTable0x90() void LegoAnimPresenter::RemoveFromWorld()
{ {
if (m_currentWorld != NULL) { if (m_currentWorld != NULL) {
m_currentWorld->RemovePresenterFromBoundaries(this); m_currentWorld->RemovePresenterFromBoundaries(this);
@ -1182,26 +1182,34 @@ void LegoAnimPresenter::SetDisabled(MxBool p_disabled)
// FUNCTION: LEGO1 0x1006c8f0 // FUNCTION: LEGO1 0x1006c8f0
// FUNCTION: BETA10 0x1005206c // FUNCTION: BETA10 0x1005206c
MxU32 LegoAnimPresenter::VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) MxU32 LegoAnimPresenter::Intersect(
Vector3& p_rayOrigin,
Vector3& p_rayDirection,
float p_rayLength,
float p_radius,
Vector3& p_intersectionPoint
)
{ {
Mx3DPointFloat a, b; Mx3DPointFloat centerToRay, rayEnd;
b = p_v2; rayEnd = p_rayDirection;
b *= p_f1; rayEnd *= p_rayLength;
b += p_v1; rayEnd += p_rayOrigin;
a = b; centerToRay = rayEnd;
a -= m_unk0xa8; centerToRay -= m_centerPoint;
float len = a.LenSquared(); float len = centerToRay.LenSquared();
if (len <= 0.0f) { if (len <= 0.0f) {
return TRUE; return TRUE;
} }
len = sqrt(len); len = sqrt(len);
if (len <= m_unk0xa4 + p_f2 && m_roiMapSize != 0 && m_roiMap != NULL) { if (len <= m_boundingRadius + p_radius && m_roiMapSize != 0 && m_roiMap != NULL) {
for (MxU32 i = 1; i <= m_roiMapSize; i++) { for (MxU32 i = 1; i <= m_roiMapSize; i++) {
if (m_roiMap[i]->GetLODCount() != 0 && m_roiMap[i]->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, FALSE)) { if (m_roiMap[i]->GetLODCount() != 0 &&
m_roiMap[i]
->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint, FALSE)) {
return TRUE; return TRUE;
} }
} }
@ -1212,7 +1220,7 @@ MxU32 LegoAnimPresenter::VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, fl
// FUNCTION: LEGO1 0x1006ca50 // FUNCTION: LEGO1 0x1006ca50
// FUNCTION: BETA10 0x100521d0 // FUNCTION: BETA10 0x100521d0
MxResult LegoAnimPresenter::VTable0x98(LegoPathBoundary* p_boundary) MxResult LegoAnimPresenter::AddActors(LegoPathBoundary* p_boundary)
{ {
for (MxU32 i = 1; i <= m_roiMapSize; i++) { for (MxU32 i = 1; i <= m_roiMapSize; i++) {
LegoEntity* entity = m_roiMap[i]->GetEntity(); LegoEntity* entity = m_roiMap[i]->GetEntity();
@ -1234,18 +1242,18 @@ void LegoLoopingAnimPresenter::StreamingTickle()
m_subscriber->FreeDataChunk(chunk); m_subscriber->FreeDataChunk(chunk);
} }
if (m_unk0x95) { if (m_animationFinished) {
ProgressTickleState(e_done); ProgressTickleState(e_done);
if (m_compositePresenter) { if (m_compositePresenter) {
if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
} }
} }
else { else {
if (m_action->GetDuration() != -1) { if (m_action->GetDuration() != -1) {
if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) { if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) {
m_unk0x95 = TRUE; m_animationFinished = TRUE;
} }
} }
} }
@ -1264,12 +1272,12 @@ void LegoLoopingAnimPresenter::PutFrame()
time = 0; time = 0;
} }
FUN_1006b9a0(m_anim, time, m_unk0x78); ApplyTransformWithVisibilityAndCam(m_anim, time, m_transform);
if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { if (m_ptAtCamROI != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) { for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
if (m_unk0x8c[i] != NULL) { if (m_ptAtCamROI[i] != NULL) {
MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); MxMatrix mat(m_ptAtCamROI[i]->GetLocal2World());
Vector3 pos(mat[0]); Vector3 pos(mat[0]);
Vector3 dir(mat[1]); Vector3 dir(mat[1]);
@ -1291,8 +1299,8 @@ void LegoLoopingAnimPresenter::PutFrame()
dir *= dirsqr; dir *= dirsqr;
up *= upsqr; up *= upsqr;
m_unk0x8c[i]->SetLocal2World(mat); m_ptAtCamROI[i]->SetLocal2World(mat);
m_unk0x8c[i]->WrappedUpdateWorldData(); m_ptAtCamROI[i]->WrappedUpdateWorldData();
} }
} }
} }
@ -1318,7 +1326,7 @@ void LegoLocomotionAnimPresenter::Init()
m_unk0xcc = -1; m_unk0xcc = -1;
m_unk0xd0 = -1; m_unk0xd0 = -1;
m_roiMapList = NULL; m_roiMapList = NULL;
m_unk0xd4 = 0; m_worldRefCounter = 0;
} }
// FUNCTION: LEGO1 0x1006d0e0 // FUNCTION: LEGO1 0x1006d0e0
@ -1387,7 +1395,7 @@ void LegoLocomotionAnimPresenter::ReadyTickle()
SendToCompositePresenter(Lego()); SendToCompositePresenter(Lego());
} }
m_unk0xd4++; m_worldRefCounter++;
} }
} }
@ -1408,7 +1416,7 @@ void LegoLocomotionAnimPresenter::StartingTickle()
// FUNCTION: LEGO1 0x1006d660 // FUNCTION: LEGO1 0x1006d660
void LegoLocomotionAnimPresenter::StreamingTickle() void LegoLocomotionAnimPresenter::StreamingTickle()
{ {
if (m_unk0xd4 == 0) { if (m_worldRefCounter == 0) {
EndAction(); EndAction();
} }
} }
@ -1423,7 +1431,7 @@ void LegoLocomotionAnimPresenter::EndAction()
// FUNCTION: LEGO1 0x1006d680 // FUNCTION: LEGO1 0x1006d680
// FUNCTION: BETA10 0x10052b3d // FUNCTION: BETA10 0x10052b3d
void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) void LegoLocomotionAnimPresenter::CreateROIAndBuildMap(LegoAnimActor* p_actor, MxFloat p_worldSpeed)
{ {
// This asserts that LegoLocomotionAnimPresenter is contained in legoanimpresenter.cpp // This asserts that LegoLocomotionAnimPresenter is contained in legoanimpresenter.cpp
AUTOLOCK(m_criticalSection); AUTOLOCK(m_criticalSection);
@ -1433,12 +1441,12 @@ void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p
const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName(); const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName();
variableTable->SetVariable(key, p_actor->GetROI()->GetName()); variableTable->SetVariable(key, p_actor->GetROI()->GetName());
FUN_100695c0(); CreateSceneROIs();
FUN_10069b10(); BuildROIMap();
if (m_roiMap != NULL) { if (m_roiMap != NULL) {
m_roiMapList->Append(m_roiMap); m_roiMapList->Append(m_roiMap);
p_actor->CreateAnimActorStruct(m_anim, p_value, m_roiMap, m_roiMapSize); p_actor->CreateAnimActorStruct(m_anim, p_worldSpeed, m_roiMap, m_roiMapSize);
m_roiMap = NULL; m_roiMap = NULL;
} }
@ -1529,21 +1537,21 @@ void LegoHideAnimPresenter::StartingTickle()
LegoLoopingAnimPresenter::StartingTickle(); LegoLoopingAnimPresenter::StartingTickle();
if (m_currentTickleState == e_streaming) { if (m_currentTickleState == e_streaming) {
FUN_1006dc10(); AssignIndiciesWithMap();
FUN_1006db40(0); ApplyVisibility(0);
} }
} }
// FUNCTION: LEGO1 0x1006db40 // FUNCTION: LEGO1 0x1006db40
// FUNCTION: BETA10 0x100531ab // FUNCTION: BETA10 0x100531ab
void LegoHideAnimPresenter::FUN_1006db40(LegoTime p_time) void LegoHideAnimPresenter::ApplyVisibility(LegoTime p_time)
{ {
FUN_1006db60(m_anim->GetRoot(), p_time); ApplyVisibility(m_anim->GetRoot(), p_time);
} }
// FUNCTION: LEGO1 0x1006db60 // FUNCTION: LEGO1 0x1006db60
// FUNCTION: BETA10 0x100531de // FUNCTION: BETA10 0x100531de
void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) void LegoHideAnimPresenter::ApplyVisibility(LegoTreeNode* p_node, LegoTime p_time)
{ {
LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData();
MxBool newB = FALSE; MxBool newB = FALSE;
@ -1564,23 +1572,23 @@ void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time)
if (boundary != NULL) { if (boundary != NULL) {
newB = data->GetVisibility(p_time); newB = data->GetVisibility(p_time);
previousB = boundary->GetFlag0x10(); previousB = boundary->GetVisibility();
boundary->SetFlag0x10(newB); boundary->SetVisibility(newB);
} }
} }
for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) { for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) {
FUN_1006db60(p_node->GetChild(i), p_time); ApplyVisibility(p_node->GetChild(i), p_time);
} }
} }
// FUNCTION: LEGO1 0x1006dc10 // FUNCTION: LEGO1 0x1006dc10
// FUNCTION: BETA10 0x100532fd // FUNCTION: BETA10 0x100532fd
void LegoHideAnimPresenter::FUN_1006dc10() void LegoHideAnimPresenter::AssignIndiciesWithMap()
{ {
LegoHideAnimStructMap anims; LegoHideAnimStructMap anims;
FUN_1006e3f0(anims, m_anim->GetRoot()); BuildMap(anims, m_anim->GetRoot());
if (m_boundaryMap != NULL) { if (m_boundaryMap != NULL) {
delete[] m_boundaryMap; delete[] m_boundaryMap;
@ -1597,7 +1605,7 @@ void LegoHideAnimPresenter::FUN_1006dc10()
// FUNCTION: LEGO1 0x1006e3f0 // FUNCTION: LEGO1 0x1006e3f0
// FUNCTION: BETA10 0x1005345e // FUNCTION: BETA10 0x1005345e
void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) void LegoHideAnimPresenter::BuildMap(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node)
{ {
LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData();
const char* name = data->GetName(); const char* name = data->GetName();
@ -1606,7 +1614,7 @@ void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeN
LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name); LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name);
if (boundary != NULL) { if (boundary != NULL) {
FUN_1006e470(p_map, data, name, boundary); CheckedAdd(p_map, data, name, boundary);
} }
else { else {
data->SetBoundaryIndex(0); data->SetBoundaryIndex(0);
@ -1615,13 +1623,13 @@ void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeN
MxS32 count = p_node->GetNumChildren(); MxS32 count = p_node->GetNumChildren();
for (MxS32 i = 0; i < count; i++) { for (MxS32 i = 0; i < count; i++) {
FUN_1006e3f0(p_map, p_node->GetChild(i)); BuildMap(p_map, p_node->GetChild(i));
} }
} }
// FUNCTION: LEGO1 0x1006e470 // FUNCTION: LEGO1 0x1006e470
// FUNCTION: BETA10 0x10053520 // FUNCTION: BETA10 0x10053520
void LegoHideAnimPresenter::FUN_1006e470( void LegoHideAnimPresenter::CheckedAdd(
LegoHideAnimStructMap& p_map, LegoHideAnimStructMap& p_map,
LegoAnimNodeData* p_data, LegoAnimNodeData* p_data,
const char* p_name, const char* p_name,

View File

@ -141,7 +141,7 @@ MxResult LegoTexturePresenter::PutData()
// FUNCTION: LEGO1 0x1004fcb0 // FUNCTION: LEGO1 0x1004fcb0
void LegoTexturePresenter::DoneTickle() void LegoTexturePresenter::DoneTickle()
{ {
if (this->m_compositePresenter && !this->m_compositePresenter->VTable0x64(2)) { if (this->m_compositePresenter && !this->m_compositePresenter->GetActionEnded(2)) {
SetTickleState(e_idle); SetTickleState(e_idle);
return; return;
} }

View File

@ -331,15 +331,15 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
m_pizzas[nextPizza].Create(this, TRUE, nextPizza); m_pizzas[nextPizza].Create(this, TRUE, nextPizza);
if (m_pizzas[nextPizza].FUN_10053b40(p_location, p_direction, p_up) != SUCCESS) { if (m_pizzas[nextPizza].CalculateArc(p_location, p_direction, p_up) != SUCCESS) {
return FAILURE; return FAILURE;
} }
MxFloat unk0x19c = *m_pizzas[nextPizza].GetUnknown0x19c(); MxFloat unk0x19c = *m_pizzas[nextPizza].GetApexParameter();
if (p_controller->FUN_1004a380( if (p_controller->FindIntersectionBoundary(
p_location, p_location,
p_direction, p_direction,
m_pizzas[nextPizza].GetUnknown0x160(), m_pizzas[nextPizza].GetCoefficients(),
boundary, boundary,
unk0x19c unk0x19c
) == SUCCESS) { ) == SUCCESS) {
@ -354,7 +354,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
direction -= m_brickster->GetROI()->GetLocal2World()[3]; direction -= m_brickster->GetROI()->GetLocal2World()[3];
local18 = FALSE; local18 = FALSE;
if (m_pizzas[nextPizza].FUN_10053cb0(p_controller, boundary, unk0x19c) == SUCCESS) { if (m_pizzas[nextPizza].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) {
p_controller->PlaceActor(&m_pizzas[nextPizza]); p_controller->PlaceActor(&m_pizzas[nextPizza]);
boundary->AddActor(&m_pizzas[nextPizza]); boundary->AddActor(&m_pizzas[nextPizza]);
m_pizzas[nextPizza].SetWorldSpeed(10.0f); m_pizzas[nextPizza].SetWorldSpeed(10.0f);
@ -362,7 +362,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
} }
} }
if (local18 && m_pizzas[nextPizza].FUN_10053d30(p_controller, unk0x19c) == SUCCESS) { if (local18 && m_pizzas[nextPizza].Shoot(p_controller, unk0x19c) == SUCCESS) {
p_controller->PlaceActor(&m_pizzas[nextPizza]); p_controller->PlaceActor(&m_pizzas[nextPizza]);
m_pizzas[nextPizza].SetWorldSpeed(10.0f); m_pizzas[nextPizza].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
@ -386,26 +386,26 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location,
m_donuts[nextDonut].Create(this, FALSE, nextDonut); m_donuts[nextDonut].Create(this, FALSE, nextDonut);
if (m_donuts[nextDonut].FUN_10053b40(p_location, p_direction, p_up) != SUCCESS) { if (m_donuts[nextDonut].CalculateArc(p_location, p_direction, p_up) != SUCCESS) {
return FAILURE; return FAILURE;
} }
MxFloat unk0x19c = *m_donuts[nextDonut].GetUnknown0x19c(); MxFloat unk0x19c = *m_donuts[nextDonut].GetApexParameter();
if (p_controller->FUN_1004a380( if (p_controller->FindIntersectionBoundary(
p_location, p_location,
p_direction, p_direction,
m_donuts[nextDonut].GetUnknown0x160(), m_donuts[nextDonut].GetCoefficients(),
boundary, boundary,
unk0x19c unk0x19c
) == SUCCESS) { ) == SUCCESS) {
if (m_donuts[nextDonut].FUN_10053cb0(p_controller, boundary, unk0x19c) == SUCCESS) { if (m_donuts[nextDonut].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) {
p_controller->PlaceActor(&m_donuts[nextDonut]); p_controller->PlaceActor(&m_donuts[nextDonut]);
boundary->AddActor(&m_donuts[nextDonut]); boundary->AddActor(&m_donuts[nextDonut]);
m_donuts[nextDonut].SetWorldSpeed(10.0f); m_donuts[nextDonut].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
} }
} }
else if (m_donuts[nextDonut].FUN_10053d30(p_controller, unk0x19c) == SUCCESS) { else if (m_donuts[nextDonut].Shoot(p_controller, unk0x19c) == SUCCESS) {
p_controller->PlaceActor(&m_donuts[nextDonut]); p_controller->PlaceActor(&m_donuts[nextDonut]);
m_donuts[nextDonut].SetWorldSpeed(10.0f); m_donuts[nextDonut].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
@ -583,13 +583,13 @@ MxLong Act3::Notify(MxParam& p_param)
m_cop1->SetActorState(LegoPathActor::c_initial); m_cop1->SetActorState(LegoPathActor::c_initial);
m_cop1->SetWorldSpeed(2.0f); m_cop1->SetWorldSpeed(2.0f);
m_cop1->VTable0xa8(); m_cop1->ApplyLocal2World();
m_cop2->SetActorState(LegoPathActor::c_initial); m_cop2->SetActorState(LegoPathActor::c_initial);
m_cop2->SetWorldSpeed(2.0f); m_cop2->SetWorldSpeed(2.0f);
m_cop2->VTable0xa8(); m_cop2->ApplyLocal2World();
m_brickster->VTable0xa8(); m_brickster->ApplyLocal2World();
m_pizzaHitSound = 0; m_pizzaHitSound = 0;
m_pizzaMissSound = 0; m_pizzaMissSound = 0;
m_copDonutSound = 0; m_copDonutSound = 0;
@ -912,44 +912,44 @@ void Act3::Enable(MxBool p_enable)
MxFloat delta = Timer()->GetTime() - m_time - 100.0f; MxFloat delta = Timer()->GetTime() - m_time - 100.0f;
m_time = -1.0f; m_time = -1.0f;
m_cop1->SetLastTime(m_cop1->GetLastTime() + delta); m_cop1->SetTransformTime(m_cop1->GetTransformTime() + delta);
m_cop1->SetActorTime(m_cop1->GetActorTime() + delta); m_cop1->SetActorTime(m_cop1->GetActorTime() + delta);
m_cop1->SetUnknown0x20(m_cop1->GetUnknown0x20() + delta); m_cop1->SetUnknown0x20(m_cop1->GetUnknown0x20() + delta);
m_cop1->SetUnknown0x1c(m_cop1->GetUnknown0x1c() + delta); m_cop1->SetUnknown0x1c(m_cop1->GetUnknown0x1c() + delta);
m_cop2->SetLastTime(m_cop2->GetLastTime() + delta); m_cop2->SetTransformTime(m_cop2->GetTransformTime() + delta);
m_cop2->SetActorTime(m_cop2->GetActorTime() + delta); m_cop2->SetActorTime(m_cop2->GetActorTime() + delta);
m_cop2->SetUnknown0x20(m_cop2->GetUnknown0x20() + delta); m_cop2->SetUnknown0x20(m_cop2->GetUnknown0x20() + delta);
m_cop2->SetUnknown0x1c(m_cop2->GetUnknown0x1c() + delta); m_cop2->SetUnknown0x1c(m_cop2->GetUnknown0x1c() + delta);
m_brickster->SetLastTime(m_brickster->GetLastTime() + delta); m_brickster->SetTransformTime(m_brickster->GetTransformTime() + delta);
m_brickster->SetActorTime(m_brickster->GetActorTime() + delta); m_brickster->SetActorTime(m_brickster->GetActorTime() + delta);
m_brickster->SetUnknown0x20(m_brickster->GetUnknown0x20() + delta); m_brickster->SetUnknown0x20(m_brickster->GetUnknown0x20() + delta);
m_brickster->SetUnknown0x24(m_brickster->GetUnknown0x24() + delta); m_brickster->SetUnknown0x24(m_brickster->GetUnknown0x24() + delta);
m_brickster->SetUnknown0x50(m_brickster->GetUnknown0x50() + delta); m_brickster->SetUnknown0x50(m_brickster->GetUnknown0x50() + delta);
m_brickster->SetUnknown0x1c(m_brickster->GetUnknown0x1c() + delta); m_brickster->SetUnknown0x1c(m_brickster->GetUnknown0x1c() + delta);
m_copter->SetLastTime(m_copter->GetLastTime() + delta); m_copter->SetTransformTime(m_copter->GetTransformTime() + delta);
m_copter->SetActorTime(m_copter->GetActorTime() + delta); m_copter->SetActorTime(m_copter->GetActorTime() + delta);
m_shark->SetLastTime(m_shark->GetLastTime() + delta); m_shark->SetTransformTime(m_shark->GetTransformTime() + delta);
m_shark->SetActorTime(m_shark->GetActorTime() + delta); m_shark->SetActorTime(m_shark->GetActorTime() + delta);
m_shark->SetUnknown0x2c(m_shark->GetUnknown0x2c() + delta); m_shark->SetUnknown0x2c(m_shark->GetUnknown0x2c() + delta);
MxS32 i; MxS32 i;
for (i = 0; i < (MxS32) sizeOfArray(m_pizzas); i++) { for (i = 0; i < (MxS32) sizeOfArray(m_pizzas); i++) {
if (m_pizzas[i].IsValid()) { if (m_pizzas[i].IsValid()) {
m_pizzas[i].SetLastTime(m_pizzas[i].GetLastTime() + delta); m_pizzas[i].SetTransformTime(m_pizzas[i].GetTransformTime() + delta);
m_pizzas[i].SetActorTime(m_pizzas[i].GetActorTime() + delta); m_pizzas[i].SetActorTime(m_pizzas[i].GetActorTime() + delta);
m_pizzas[i].SetUnknown0x158(m_pizzas[i].GetUnknown0x158() + delta); m_pizzas[i].SetRotateTimeout(m_pizzas[i].GetRotateTimeout() + delta);
} }
} }
for (i = 0; i < (MxS32) sizeOfArray(m_donuts); i++) { for (i = 0; i < (MxS32) sizeOfArray(m_donuts); i++) {
if (m_donuts[i].IsValid()) { if (m_donuts[i].IsValid()) {
m_donuts[i].SetLastTime(m_donuts[i].GetLastTime() + delta); m_donuts[i].SetTransformTime(m_donuts[i].GetTransformTime() + delta);
m_donuts[i].SetActorTime(m_donuts[i].GetActorTime() + delta); m_donuts[i].SetActorTime(m_donuts[i].GetActorTime() + delta);
m_donuts[i].SetUnknown0x158(m_donuts[i].GetUnknown0x158() + delta); m_donuts[i].SetRotateTimeout(m_donuts[i].GetRotateTimeout() + delta);
} }
} }
@ -959,7 +959,7 @@ void Act3::Enable(MxBool p_enable)
InputManager()->SetWorld(this); InputManager()->SetWorld(this);
InputManager()->Register(this); InputManager()->Register(this);
SetUserActor(m_copter); SetUserActor(m_copter);
m_copter->VTable0xa8(); m_copter->ApplyLocal2World();
SetAppCursor(e_cursorArrow); SetAppCursor(e_cursorArrow);
} }
} }

View File

@ -878,7 +878,7 @@ void Isle::CheckAreaExiting()
case LegoGameState::e_vehicleExited: { case LegoGameState::e_vehicleExited: {
MxMatrix mat(UserActor()->GetROI()->GetLocal2World()); MxMatrix mat(UserActor()->GetROI()->GetLocal2World());
LegoPathBoundary* boundary = UserActor()->GetBoundary(); LegoPathBoundary* boundary = UserActor()->GetBoundary();
((IslePathActor*) UserActor())->VTable0xec(mat, boundary, TRUE); ((IslePathActor*) UserActor())->UpdateWorld(mat, boundary, TRUE);
break; break;
} }
case LegoGameState::e_infocenterExited: case LegoGameState::e_infocenterExited:

View File

@ -534,7 +534,7 @@ void LegoAct2::Enable(MxBool p_enable)
GameState()->SetActor(LegoActor::c_pepper); GameState()->SetActor(LegoActor::c_pepper);
m_pepper = FindROI("pepper"); m_pepper = FindROI("pepper");
((IslePathActor*) m_pepper->GetEntity())->VTable0xec(m_transformOnDisable, m_boundaryOnDisable, TRUE); ((IslePathActor*) m_pepper->GetEntity())->UpdateWorld(m_transformOnDisable, m_boundaryOnDisable, TRUE);
if (GameState()->m_previousArea == LegoGameState::e_infomain) { if (GameState()->m_previousArea == LegoGameState::e_infomain) {
GameState()->StopArea(LegoGameState::e_infomain); GameState()->StopArea(LegoGameState::e_infomain);
@ -1209,19 +1209,19 @@ MxResult LegoAct2::InitializeShooting()
ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim0"); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim0");
assert(ap); assert(ap);
ap->FUN_1006d680(m_unk0x1138, 0.0f); ap->CreateROIAndBuildMap(m_unk0x1138, 0.0f);
ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim2"); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim2");
assert(ap); assert(ap);
ap->FUN_1006d680(m_unk0x1138, 6.0f); ap->CreateROIAndBuildMap(m_unk0x1138, 6.0f);
ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim3"); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim3");
assert(ap); assert(ap);
ap->FUN_1006d680(m_unk0x1138, 3.0f); ap->CreateROIAndBuildMap(m_unk0x1138, 3.0f);
ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "BrShoot"); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "BrShoot");
assert(ap); assert(ap);
ap->FUN_1006d680(m_unk0x1138, -1.0f); ap->CreateROIAndBuildMap(m_unk0x1138, -1.0f);
actor->SetWorldSpeed(0.0f); actor->SetWorldSpeed(0.0f);
m_unk0x1138->InitializeNextShot(); m_unk0x1138->InitializeNextShot();

View File

@ -290,11 +290,11 @@ class LegoAnimNodeData : public LegoTreeNodeData {
// SIZE 0x08 // SIZE 0x08
struct LegoAnimActorEntry { struct LegoAnimActorEntry {
enum { enum {
e_actorType2 = 2, e_managedLegoActor = 2,
e_actorType3 = 3, e_managedInvisibleRoiTrimmed = 3,
e_actorType4 = 4, e_managedInvisibleRoi = 4,
e_actorType5 = 5, e_sceneRoi1 = 5,
e_actorType6 = 6, e_sceneRoi2 = 6,
}; };
LegoChar* m_name; // 0x00 LegoChar* m_name; // 0x00

View File

@ -37,7 +37,7 @@ class LegoWEGEdge : public LegoWEEdge {
c_bit1 = 0x01, c_bit1 = 0x01,
c_bit2 = 0x02, c_bit2 = 0x02,
c_bit3 = 0x04, c_bit3 = 0x04,
c_bit5 = 0x10 c_visible = 0x10
}; };
LegoWEGEdge(); LegoWEGEdge();
@ -46,9 +46,9 @@ class LegoWEGEdge : public LegoWEEdge {
LegoS32 LinkEdgesAndFaces() override; // vtable+0x04 LegoS32 LinkEdgesAndFaces() override; // vtable+0x04
// FUNCTION: BETA10 0x100270c0 // FUNCTION: BETA10 0x100270c0
LegoU32 GetFlag0x10() LegoU32 GetVisibility()
{ {
if (m_flags & c_bit5) { if (m_flags & c_visible) {
return FALSE; return FALSE;
} }
else { else {
@ -67,13 +67,13 @@ class LegoWEGEdge : public LegoWEEdge {
const LegoChar* GetName() { return m_name; } const LegoChar* GetName() { return m_name; }
// FUNCTION: BETA10 0x1005d5f0 // FUNCTION: BETA10 0x1005d5f0
void SetFlag0x10(LegoU32 p_disable) void SetVisibility(LegoU32 p_disable)
{ {
if (p_disable) { if (p_disable) {
m_flags &= ~c_bit5; m_flags &= ~c_visible;
} }
else { else {
m_flags |= c_bit5; m_flags |= c_visible;
} }
} }

View File

@ -0,0 +1,88 @@
#include "legospline.h"
#include "mxgeometry/mxmatrix.h"
DECOMP_SIZE_ASSERT(LegoSpline, 0x50)
// FUNCTION: LEGO1 0x1009a0f0
LegoSpline::LegoSpline()
{
for (LegoS32 i = 0; i < sizeOfArray(m_coefficents); i++) {
m_coefficents[i].Clear();
}
}
// FUNCTION: LEGO1 0x1009a130
LegoSpline::~LegoSpline()
{
}
// FUNCTION: LEGO1 0x1009a140
// FUNCTION: BETA10 0x10182c2f
void LegoSpline::SetSpline(
const Vector3& p_start,
const Vector3& p_tangentAtStart,
const Vector3& p_end,
const Vector3& p_tangentAtEnd
)
{
m_coefficents[0] = p_start;
m_coefficents[1] = p_tangentAtStart;
for (LegoS32 i = 0; i < 3; i++) {
m_coefficents[2][i] = (p_end[i] - p_start[i]) * 3.0f - p_tangentAtStart[i] * 2.0f - p_tangentAtEnd[i];
m_coefficents[3][i] = (p_start[i] - p_end[i]) * 2.0f + p_tangentAtEnd[i] + p_tangentAtStart[i];
}
}
// FUNCTION: LEGO1 0x1009a1e0
// FUNCTION: BETA10 0x10182d61
LegoResult LegoSpline::Evaluate(float p_alpha, Matrix4& p_mat, Vector3& p_up, LegoU32 p_reverse)
{
Vector3 position(p_mat[3]);
Vector3 right(p_mat[0]);
Vector3 up(p_mat[1]);
Vector3 dir(p_mat[2]);
if (isnan(p_alpha) || p_alpha <= 0.001) {
position = m_coefficents[0];
dir = m_coefficents[1];
}
else if (p_alpha >= 0.999) {
position = m_coefficents[0];
position += m_coefficents[1];
position += m_coefficents[2];
position += m_coefficents[3];
for (LegoS32 i = 0; i < 3; i++) {
dir[i] = m_coefficents[1][i] + m_coefficents[2][i] * 2.0f + m_coefficents[3][i] * 3.0f;
}
}
else {
float alpha_squared = p_alpha * p_alpha;
float alpha_cubed = alpha_squared * p_alpha;
for (LegoS32 i = 0; i < 3; i++) {
position[i] = m_coefficents[0][i] + m_coefficents[1][i] * p_alpha + m_coefficents[2][i] * alpha_squared +
m_coefficents[3][i] * alpha_cubed;
dir[i] =
m_coefficents[1][i] + m_coefficents[2][i] * p_alpha * 2.0f + m_coefficents[3][i] * alpha_squared * 3.0f;
}
}
if (p_reverse) {
dir *= -1.0f;
}
if (dir.Unitize() != 0) {
return FAILURE;
}
right.EqualsCross(p_up, dir);
if (right.Unitize() != 0) {
return FAILURE;
}
up.EqualsCross(dir, right);
return SUCCESS;
}

View File

@ -0,0 +1,27 @@
#ifndef __LEGOSPLINE_H
#define __LEGOSPLINE_H
#include "legotypes.h"
#include "mxgeometry/mxgeometry3d.h"
class Matrix4;
// SIZE 0x50
class LegoSpline {
public:
LegoSpline();
~LegoSpline();
void SetSpline(
const Vector3& p_start,
const Vector3& p_tangentAtStart,
const Vector3& p_end,
const Vector3& p_tangentAtEnd
);
LegoResult Evaluate(float p_alpha, Matrix4& p_mat, Vector3& p_v, LegoU32 p_reverse);
private:
Mx3DPointFloat m_coefficents[4]; // 0x00
};
#endif // __LEGOSPLINE_H

View File

@ -1,86 +0,0 @@
#include "legounknown.h"
#include "mxgeometry/mxmatrix.h"
DECOMP_SIZE_ASSERT(LegoUnknown, 0x50)
// FUNCTION: LEGO1 0x1009a0f0
LegoUnknown::LegoUnknown()
{
for (LegoS32 i = 0; i < sizeOfArray(m_unk0x00); i++) {
m_unk0x00[i].Clear();
}
}
// FUNCTION: LEGO1 0x1009a130
LegoUnknown::~LegoUnknown()
{
}
// FUNCTION: LEGO1 0x1009a140
// FUNCTION: BETA10 0x10182c2f
void LegoUnknown::FUN_1009a140(
const Vector3& p_point1,
const Vector3& p_point2,
const Vector3& p_point3,
const Vector3& p_point4
)
{
m_unk0x00[0] = p_point1;
m_unk0x00[1] = p_point2;
for (LegoS32 i = 0; i < 3; i++) {
m_unk0x00[2][i] = (p_point3[i] - p_point1[i]) * 3.0f - p_point2[i] * 2.0f - p_point4[i];
m_unk0x00[3][i] = (p_point1[i] - p_point3[i]) * 2.0f + p_point4[i] + p_point2[i];
}
}
// FUNCTION: LEGO1 0x1009a1e0
// FUNCTION: BETA10 0x10182d61
LegoResult LegoUnknown::FUN_1009a1e0(float p_f1, Matrix4& p_mat, Vector3& p_v, LegoU32 p_und)
{
Vector3 v1(p_mat[3]);
Vector3 v2(p_mat[0]);
Vector3 v3(p_mat[1]);
Vector3 v4(p_mat[2]);
if (isnan(p_f1) || p_f1 <= 0.001) {
v1 = m_unk0x00[0];
v4 = m_unk0x00[1];
}
else if (p_f1 >= 0.999) {
v1 = m_unk0x00[0];
v1 += m_unk0x00[1];
v1 += m_unk0x00[2];
v1 += m_unk0x00[3];
for (LegoS32 i = 0; i < 3; i++) {
v4[i] = m_unk0x00[1][i] + m_unk0x00[2][i] * 2.0f + m_unk0x00[3][i] * 3.0f;
}
}
else {
float local30 = p_f1 * p_f1;
float local34 = local30 * p_f1;
for (LegoS32 i = 0; i < 3; i++) {
v1[i] = m_unk0x00[0][i] + m_unk0x00[1][i] * p_f1 + m_unk0x00[2][i] * local30 + m_unk0x00[3][i] * local34;
v4[i] = m_unk0x00[1][i] + m_unk0x00[2][i] * p_f1 * 2.0f + m_unk0x00[3][i] * local30 * 3.0f;
}
}
if (p_und) {
v4 *= -1.0f;
}
if (v4.Unitize() != 0) {
return FAILURE;
}
v2.EqualsCross(p_v, v4);
if (v2.Unitize() != 0) {
return FAILURE;
}
v3.EqualsCross(v4, v2);
return SUCCESS;
}

View File

@ -1,27 +0,0 @@
#ifndef __LEGOUNKNOWN_H
#define __LEGOUNKNOWN_H
#include "legotypes.h"
#include "mxgeometry/mxgeometry3d.h"
class Matrix4;
// SIZE 0x50
class LegoUnknown {
public:
LegoUnknown();
~LegoUnknown();
void FUN_1009a140(
const Vector3& p_point1,
const Vector3& p_point2,
const Vector3& p_point3,
const Vector3& p_point4
);
LegoResult FUN_1009a1e0(float p_f1, Matrix4& p_mat, Vector3& p_v, LegoU32 p_und);
private:
Mx3DPointFloat m_unk0x00[4]; // 0x00
};
#endif // __LEGOUNKNOWN_H

View File

@ -163,11 +163,11 @@
#include "lego/sources/geom/legowegedge.h" #include "lego/sources/geom/legowegedge.h"
#include "lego/sources/misc/legocontainer.h" #include "lego/sources/misc/legocontainer.h"
#include "lego/sources/misc/legoimage.h" #include "lego/sources/misc/legoimage.h"
#include "lego/sources/misc/legospline.h"
#include "lego/sources/misc/legostorage.h" #include "lego/sources/misc/legostorage.h"
#include "lego/sources/misc/legotexture.h" #include "lego/sources/misc/legotexture.h"
#include "lego/sources/misc/legotree.h" #include "lego/sources/misc/legotree.h"
#include "lego/sources/misc/legotypes.h" #include "lego/sources/misc/legotypes.h"
#include "lego/sources/misc/legounknown.h"
#include "lego/sources/misc/legoutil.h" #include "lego/sources/misc/legoutil.h"
#include "lego/sources/misc/version.h" #include "lego/sources/misc/version.h"
#include "lego/sources/roi/legolod.h" #include "lego/sources/roi/legolod.h"

View File

@ -43,15 +43,15 @@ class MxCompositePresenter : public MxPresenter {
void SetTickleState(TickleState p_tickleState) override; // vtable+0x44 void SetTickleState(TickleState p_tickleState) override; // vtable+0x44
MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48
void Enable(MxBool p_enable) override; // vtable+0x54 void Enable(MxBool p_enable) override; // vtable+0x54
virtual void VTable0x58(MxEndActionNotificationParam& p_param); // vtable+0x58 virtual void HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0x58
virtual void VTable0x5c(MxNotificationParam& p_param); // vtable+0x5c virtual void HandlePresenter(MxNotificationParam& p_param); // vtable+0x5c
virtual void VTable0x60(MxPresenter* p_presenter); // vtable+0x60 virtual void AdvanceSerialAction(MxPresenter* p_presenter); // vtable+0x60
// FUNCTION: LEGO1 0x1000caf0 // FUNCTION: LEGO1 0x1000caf0
virtual MxBool VTable0x64(undefined4 p_undefined) virtual MxBool GetActionEnded(undefined4 p_undefined)
{ {
if (m_compositePresenter) { if (m_compositePresenter) {
return m_compositePresenter->VTable0x64(p_undefined); return m_compositePresenter->GetActionEnded(p_undefined);
} }
return TRUE; return TRUE;
} // vtable+0x64 } // vtable+0x64

View File

@ -62,7 +62,7 @@ class MxVideoManager : public MxPresentationManager {
LPDIRECT3D2 m_pDirect3D; // 0x54 LPDIRECT3D2 m_pDirect3D; // 0x54
MxDisplaySurface* m_displaySurface; // 0x58 MxDisplaySurface* m_displaySurface; // 0x58
MxRegion* m_region; // 0x5c MxRegion* m_region; // 0x5c
MxBool m_unk0x60; // 0x60 MxBool m_created; // 0x60
}; };
#endif // MXVIDEOMANAGER_H #endif // MXVIDEOMANAGER_H

View File

@ -117,10 +117,10 @@ MxLong MxCompositePresenter::Notify(MxParam& p_param)
switch (param.GetNotification()) { switch (param.GetNotification()) {
case c_notificationEndAction: case c_notificationEndAction:
VTable0x58((MxEndActionNotificationParam&) p_param); HandleEndAction((MxEndActionNotificationParam&) p_param);
break; break;
case c_notificationPresenter: case c_notificationPresenter:
VTable0x5c((MxNotificationParam&) p_param); HandlePresenter((MxNotificationParam&) p_param);
break; break;
default: default:
assert(0); assert(0);
@ -131,7 +131,7 @@ MxLong MxCompositePresenter::Notify(MxParam& p_param)
} }
// FUNCTION: LEGO1 0x100b67f0 // FUNCTION: LEGO1 0x100b67f0
void MxCompositePresenter::VTable0x58(MxEndActionNotificationParam& p_param) void MxCompositePresenter::HandleEndAction(MxEndActionNotificationParam& p_param)
{ {
MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); MxPresenter* presenter = (MxPresenter*) p_param.GetSender();
MxDSAction* action = p_param.GetAction(); MxDSAction* action = p_param.GetAction();
@ -177,7 +177,7 @@ void MxCompositePresenter::VTable0x58(MxEndActionNotificationParam& p_param)
} }
// FUNCTION: LEGO1 0x100b69b0 // FUNCTION: LEGO1 0x100b69b0
void MxCompositePresenter::VTable0x5c(MxNotificationParam& p_param) void MxCompositePresenter::HandlePresenter(MxNotificationParam& p_param)
{ {
if (!m_list.empty()) { if (!m_list.empty()) {
MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); MxPresenter* presenter = (MxPresenter*) p_param.GetSender();
@ -218,13 +218,13 @@ void MxCompositePresenter::VTable0x5c(MxNotificationParam& p_param)
} }
// FUNCTION: LEGO1 0x100b6b40 // FUNCTION: LEGO1 0x100b6b40
void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter) void MxCompositePresenter::AdvanceSerialAction(MxPresenter* p_presenter)
{ {
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {
if (*it == p_presenter) { if (*it == p_presenter) {
if (++it == m_list.end()) { if (++it == m_list.end()) {
if (m_compositePresenter) { if (m_compositePresenter) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
} }
else if (m_action->IsA("MxDSSerialAction")) { else if (m_action->IsA("MxDSSerialAction")) {

View File

@ -156,7 +156,8 @@ void MxMediaPresenter::EndAction()
m_currentChunk = NULL; m_currentChunk = NULL;
if (m_action->GetFlags() & MxDSAction::c_world && (!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) { if (m_action->GetFlags() & MxDSAction::c_world &&
(!m_compositePresenter || !m_compositePresenter->GetActionEnded(2))) {
MxPresenter::Enable(FALSE); MxPresenter::Enable(FALSE);
SetTickleState(e_idle); SetTickleState(e_idle);
} }

View File

@ -134,7 +134,7 @@ void MxStillPresenter::StreamingTickle()
ProgressTickleState(e_repeating); ProgressTickleState(e_repeating);
if (m_action->GetDuration() == -1 && m_compositePresenter) { if (m_action->GetDuration() == -1 && m_compositePresenter) {
m_compositePresenter->VTable0x60(this); m_compositePresenter->AdvanceSerialAction(this);
} }
} }
} }

View File

@ -43,7 +43,7 @@ MxResult MxVideoManager::Init()
m_displaySurface = NULL; m_displaySurface = NULL;
m_region = NULL; m_region = NULL;
m_videoParam.SetPalette(NULL); m_videoParam.SetPalette(NULL);
m_unk0x60 = FALSE; m_created = FALSE;
return SUCCESS; return SUCCESS;
} }
@ -73,7 +73,7 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor)
delete m_videoParam.GetPalette(); delete m_videoParam.GetPalette();
} }
if (m_unk0x60) { if (m_created) {
if (m_pDirectDraw) { if (m_pDirectDraw) {
m_pDirectDraw->Release(); m_pDirectDraw->Release();
} }
@ -154,7 +154,7 @@ MxResult MxVideoManager::VTable0x28(
MxBool locked = FALSE; MxBool locked = FALSE;
MxResult status = FAILURE; MxResult status = FAILURE;
m_unk0x60 = FALSE; m_created = FALSE;
if (MxPresentationManager::Create() != SUCCESS) { if (MxPresentationManager::Create() != SUCCESS) {
goto done; goto done;
@ -229,7 +229,7 @@ MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS,
MxResult status = FAILURE; MxResult status = FAILURE;
HWND hWnd = NULL; HWND hWnd = NULL;
m_unk0x60 = TRUE; m_created = TRUE;
if (MxPresentationManager::Create() != SUCCESS) { if (MxPresentationManager::Create() != SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxPresentationManager::Create failed"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxPresentationManager::Create failed");

View File

@ -123,7 +123,7 @@ class Vector4 : public Vector3 {
Vector4(float* p_data) : Vector3(p_data) {} Vector4(float* p_data) : Vector3(p_data) {}
// Some code initializes a Vector4 from a `const float*` source. // Some code initializes a Vector4 from a `const float*` source.
// Example: `LegoCarBuild::VTable0x6c` // Example: `LegoCarBuild::CheckIntersections`
// Vector4 however is a class that can mutate its underlying source, making // Vector4 however is a class that can mutate its underlying source, making
// initialization with a const source fundamentally incompatible. // initialization with a const source fundamentally incompatible.
// BETA10 appears to have two separate constructors for Vector4 as well, // BETA10 appears to have two separate constructors for Vector4 as well,

63
docs/README.md Normal file
View File

@ -0,0 +1,63 @@
# LEGO Island File Format Documentation
This folder contains documentation for LEGO Island's custom binary file formats using [Kaitai Struct](https://kaitai.io/), a declarative language for describing binary data structures.
## What is Kaitai Struct?
Kaitai Struct allows you to define binary formats in a YAML-based `.ksy` file, which can then be:
- Compiled into parser libraries for [many programming languages](https://kaitai.io/#quick-start) (C++, Python, JavaScript, etc.)
- Visualized interactively using the [Kaitai Struct Visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer)
- Dumped to human-readable formats using `ksdump`
<img width="1877" height="706" alt="image" src="https://github.com/user-attachments/assets/0d124219-1208-48ce-83bb-f433d9bb84b1" />
## Documented Formats
| File | Extension | Description |
|------|-----------|-------------|
| [`savegame.ksy`](/docs/savegame.ksy) | `.GS` | Main game save data (game state, progress, customizations) |
| [`players.ksy`](/docs/players.ksy) | `.gsi` | Player profile save data (usernames) |
| [`history.ksy`](/docs/history.ksy) | `.gsi` | Score history and high scores |
## Using the Tools
### Installation
See the [Kaitai Struct Visualizer installation instructions](https://github.com/kaitai-io/kaitai_struct_visualizer?tab=readme-ov-file#downloading-and-installing) for setup details.
### Kaitai Struct Visualizer (ksv)
The [Kaitai Struct Visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) (`ksv`) provides an interactive terminal UI for exploring binary files.
```bash
# View a save game file
ksv samples/G0.GS savegame.ksy
# View a Players.gsi file
ksv samples/Players.gsi players.ksy
# View a History.gsi file
ksv samples/History.gsi history.ksy
```
### Kaitai Struct Dump (ksdump)
`ksdump` outputs the parsed structure as JSON or YAML for scripting and inspection.
```bash
# Dump a save game to JSON
ksdump --format json samples/G0.GS savegame.ksy
# Dump Players.gsi to JSON
ksdump --format json samples/Players.gsi players.ksy
# Dump History.gsi to YAML
ksdump --format yaml samples/History.gsi history.ksy
```
## Sample Files
The [`samples/`](/docs/samples/) directory contains example save files for testing:
- `G0.GS`, `G1.GS`, `G2.GS` - Sample main game save files (slots 0, 1, 2)
- `Players.gsi` - Sample player profile data
- `History.gsi` - Sample score history data

125
docs/history.ksy Normal file
View File

@ -0,0 +1,125 @@
meta:
id: history
title: Score History Save File
application: LEGO Island
file-extension: gsi
license: CC0-1.0
endian: le
doc: |
Score history save data for LEGO Island (1997). Stores up to 20 player
score entries, tracking high scores across all missions and characters.
The file is located at `<save_path>/History.gsi` where save_path is
typically the game's installation directory.
seq:
- id: next_player_id
type: s2
doc: |
The next player ID to be assigned when a new player profile is created.
Increments each time a new player is added, ensuring unique IDs.
- id: count
type: s2
doc: Number of score entries in the history (0-20 max).
- id: entries
type: score_entry
repeat: expr
repeat-expr: count
doc: Array of score history entries, sorted by total score descending.
types:
score_entry:
doc: |
A single score history entry containing a player's high scores across
all minigames and characters. Total serialized size is 45 bytes
(2 for index + 43 for score_item data).
seq:
- id: index
type: s2
doc: Array index of this entry (0 to count-1). Stored redundantly in file.
- id: total_score
type: s2
doc: Sum of all individual high scores across all missions and actors.
- id: scores
type: mission_scores
doc: High scores organized by mission type, each containing scores per actor.
- id: name
type: username
doc: The player's username associated with these scores.
- id: player_id
type: s2
doc: Unique player identifier matching the player's profile.
mission_scores:
doc: |
High scores for all 5 missions. Each mission contains scores for all
5 playable actors.
seq:
- id: car_race
type: actor_scores
doc: Car Race mission high scores.
- id: jetski_race
type: actor_scores
doc: Jetski Race mission high scores.
- id: pizza_delivery
type: actor_scores
doc: Pizza Delivery mission high scores.
- id: tow_track
type: actor_scores
doc: Tow Track mission high scores.
- id: ambulance
type: actor_scores
doc: Ambulance mission high scores.
actor_scores:
doc: |
High scores for a single mission across all 5 playable actors.
seq:
- id: pepper
type: u1
enum: score_color
doc: High score for Pepper.
- id: mama
type: u1
enum: score_color
doc: High score for Mama.
- id: papa
type: u1
enum: score_color
doc: High score for Papa.
- id: nick
type: u1
enum: score_color
doc: High score for Nick.
- id: laura
type: u1
enum: score_color
doc: High score for Laura.
username:
doc: |
A player username consisting of up to 7 letters. Each letter is stored
as a signed 16-bit index. The struct is always 14 bytes (0x0e).
seq:
- id: letters
type: s2
repeat: expr
repeat-expr: 7
doc: |
Letter indices for the username characters:
- 0-25: Standard alphabet (0=A, 1=B, ..., 25=Z)
- 29: International ä, å, or ñ (language-dependent)
- 30: International ö or æ (language-dependent)
- 31: International ß or ø (language-dependent)
- 32: International ü
- -1 (0xFFFF): Empty/unused position
Unused positions are filled with -1. A name shorter than 7
characters will have trailing -1 values.
enums:
score_color:
0: grey
1: yellow
2: blue
3: red

48
docs/players.ksy Normal file
View File

@ -0,0 +1,48 @@
meta:
id: players
title: Players Save File
application: LEGO Island
file-extension: gsi
license: CC0-1.0
endian: le
doc: |
Player profile save data for LEGO Island (1997). Stores up to 9 player
profiles, each identified by a 7-character username. Usernames are stored
as letter indices rather than ASCII characters.
The file is located at `<save_path>/Players.gsi` where save_path is
typically the game's installation directory.
seq:
- id: count
type: s2
doc: |
Number of saved player profiles. The game supports a maximum of 9
players; when a 10th player is added, the oldest profile is deleted.
- id: entries
type: username
repeat: expr
repeat-expr: count
doc: Array of player username entries, ordered by most recently played.
types:
username:
doc: |
A player username consisting of up to 7 letters. Each letter is stored
as a signed 16-bit index. The struct is always 14 bytes (0x0e).
seq:
- id: letters
type: s2
repeat: expr
repeat-expr: 7
doc: |
Letter indices for the username characters:
- 0-25: Standard alphabet (0=A, 1=B, ..., 25=Z)
- 29: International ä, å, or ñ (language-dependent)
- 30: International ö or æ (language-dependent)
- 31: International ß or ø (language-dependent)
- 32: International ü
- -1 (0xFFFF): Empty/unused position
Unused positions are filled with -1. A name shorter than 7
characters will have trailing -1 values.

BIN
docs/samples/G0.GS Executable file

Binary file not shown.

BIN
docs/samples/G1.GS Executable file

Binary file not shown.

BIN
docs/samples/G2.GS Executable file

Binary file not shown.

BIN
docs/samples/History.gsi Executable file

Binary file not shown.

BIN
docs/samples/Players.gsi Executable file

Binary file not shown.

1014
docs/savegame.ksy Normal file

File diff suppressed because it is too large Load Diff