Compare commits
No commits in common. "base" and "map_exit" have entirely different histories.
3157 changed files with 131627 additions and 144267 deletions
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
# We base things of WebKit + Allman braces
|
||||
# Compatible with clang-format-22 (enforced by tools/run_clang_format.py)
|
||||
# Compatible with clang-format-20
|
||||
Language: Cpp
|
||||
|
||||
# Access modifiers
|
||||
|
|
@ -28,7 +28,8 @@ AllowShortFunctionsOnASingleLine: None
|
|||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: None
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
LambdaBodyIndentation: Signature
|
||||
|
||||
# Note: LambdaBodyIndentation not available in clang-format-20
|
||||
|
||||
# Template declarations
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
|
|
@ -70,8 +71,6 @@ BinPackParameters: false
|
|||
# Namespaces
|
||||
CompactNamespaces: false
|
||||
NamespaceIndentation: None
|
||||
WrapNamespaceBodyWithEmptyLines: Always
|
||||
SeparateDefinitionBlocks: Always
|
||||
|
||||
# Braced lists and initializers
|
||||
Cpp11BracedListStyle: false
|
||||
|
|
@ -90,7 +89,8 @@ MaxEmptyLinesToKeep: 1
|
|||
# Pointer and reference alignment
|
||||
PointerAlignment: Left
|
||||
ReferenceAlignment: Pointer
|
||||
QualifierAlignment: Left # West Const
|
||||
|
||||
# Note: QualifierAlignment not available in clang-format-20, use manual const placement
|
||||
|
||||
# Comments
|
||||
ReflowComments: Always
|
||||
|
|
|
|||
2
.gitattributes
vendored
2
.gitattributes
vendored
|
|
@ -12,8 +12,6 @@
|
|||
*.h text eol=lf
|
||||
*.sql text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.yaml text eol=lf
|
||||
*.yml text eol=lf
|
||||
|
||||
# Retaining CRLF line ends in the documentation dir (for now..)
|
||||
*.txt text eol=crlf
|
||||
|
|
|
|||
2
.github/workflows/codeql_analysis.yml
vendored
2
.github/workflows/codeql_analysis.yml
vendored
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y software-properties-common cmake libmariadb-dev-compat libluajit-5.1-dev libzmq3-dev zlib1g-dev libssl-dev binutils-dev libzstd-dev libdwarf-dev
|
||||
sudo apt-get install -y software-properties-common cmake libmariadb-dev-compat libluajit-5.1-dev libzmq3-dev zlib1g-dev libssl-dev binutils-dev libzstd-dev
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
|
|
|||
2
.github/workflows/docker_test.yml
vendored
2
.github/workflows/docker_test.yml
vendored
|
|
@ -119,7 +119,7 @@ jobs:
|
|||
- name: Run xi_test
|
||||
id: xi_test
|
||||
continue-on-error: true
|
||||
run: docker exec test-server /bin/bash -c './xi_test --keep-going --retry 5 --output log/tests.ctrf.json'
|
||||
run: docker exec test-server /bin/bash -c './xi_test --keep-going --output log/tests.ctrf.json'
|
||||
|
||||
- name: Publish Test Report
|
||||
if: ${{ !cancelled() }}
|
||||
|
|
|
|||
41
.github/workflows/pr_checks.yml
vendored
41
.github/workflows/pr_checks.yml
vendored
|
|
@ -196,50 +196,31 @@ jobs:
|
|||
id: changed
|
||||
run: |
|
||||
mapfile -t changed_files < changed-files.txt
|
||||
yaml_files=()
|
||||
other_files=()
|
||||
data_files=()
|
||||
for f in "${changed_files[@]}"; do
|
||||
if [[ $f == data/*.yaml || $f == data/*.yml ]]; then
|
||||
yaml_files+=("$f")
|
||||
elif [[ $f == data/* ]]; then
|
||||
other_files+=("$f")
|
||||
if [[ $f == data/* ]]; then
|
||||
data_files+=("$f")
|
||||
fi
|
||||
done
|
||||
echo "yaml=${yaml_files[*]}" >> "$GITHUB_OUTPUT"
|
||||
echo "other=${other_files[*]}" >> "$GITHUB_OUTPUT"
|
||||
echo "Changed YAML: ${yaml_files[*]}"
|
||||
echo "Changed other: ${other_files[*]}"
|
||||
echo "files=${data_files[*]}" >> "$GITHUB_OUTPUT"
|
||||
echo "Changed data files: ${data_files[*]}"
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
if: steps.changed.outputs.yaml != '' || steps.changed.outputs.other != ''
|
||||
|
||||
- name: Setup Python
|
||||
if: steps.changed.outputs.yaml != ''
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Install Python dependencies
|
||||
if: steps.changed.outputs.yaml != ''
|
||||
run: python -m pip install pyyaml ruamel.yaml
|
||||
|
||||
- name: Check YAML formatting
|
||||
if: steps.changed.outputs.yaml != ''
|
||||
run: python tools/yaml/format.py ${{ steps.changed.outputs.yaml }} --check
|
||||
if: steps.changed.outputs.files != ''
|
||||
|
||||
- name: Cache prettier results
|
||||
if: steps.changed.outputs.other != ''
|
||||
if: steps.changed.outputs.files != ''
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: /tmp/prettier-cache
|
||||
key: prettier-cache-${{ hashFiles('data/**/*.json') }}
|
||||
key: prettier-cache-${{ hashFiles('data/**/*.yaml', 'data/**/*.json') }}
|
||||
restore-keys: prettier-cache-
|
||||
|
||||
- name: Run prettier
|
||||
if: steps.changed.outputs.other != ''
|
||||
if: steps.changed.outputs.files != ''
|
||||
run: |
|
||||
set +e
|
||||
FAILED=$(npx --yes prettier@3 --cache --cache-strategy content --cache-location /tmp/prettier-cache --list-different ${{ steps.changed.outputs.other }})
|
||||
FAILED=$(npx --yes prettier@3 --cache --cache-strategy content --cache-location /tmp/prettier-cache --list-different ${{ steps.changed.outputs.files }})
|
||||
set -e
|
||||
if [ -z "$FAILED" ]; then
|
||||
echo "All files use Prettier code style!"
|
||||
|
|
@ -316,7 +297,7 @@ jobs:
|
|||
- runner: macos-26
|
||||
test_modules: false
|
||||
multi_process: false
|
||||
xi_test: true
|
||||
xi_test: false
|
||||
startup_checks: true
|
||||
- runner: ubuntu-26.04
|
||||
test_modules: false
|
||||
|
|
|
|||
16
.github/workflows/runner_build.yml
vendored
16
.github/workflows/runner_build.yml
vendored
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
- name: Install dependencies (macOS)
|
||||
if: ${{ runner.os == 'macOS' && env.SKIP_BUILD != 'true' }}
|
||||
run: |
|
||||
brew install --quiet \
|
||||
brew update && brew install --quiet \
|
||||
mariadb \
|
||||
zeromq \
|
||||
luajit \
|
||||
|
|
@ -108,7 +108,7 @@ jobs:
|
|||
- name: Setup LLVM Clang (macOS)
|
||||
if: ${{ runner.os == 'macOS' && startsWith(inputs.compiler, 'clang') && env.SKIP_BUILD != 'true' }}
|
||||
run: |
|
||||
brew install --quiet \
|
||||
brew update && brew install --quiet \
|
||||
llvm@${{ inputs.compiler_version }} \
|
||||
lld@${{ inputs.compiler_version }}
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ jobs:
|
|||
- name: Setup GCC (macOS)
|
||||
if: ${{ runner.os == 'macOS' && startsWith(inputs.compiler, 'gcc') && env.SKIP_BUILD != 'true' }}
|
||||
run: |
|
||||
brew install --quiet gcc@${{ inputs.compiler_version }}
|
||||
brew update && brew install --quiet gcc@${{ inputs.compiler_version }}
|
||||
GCC_PREFIX=$(brew --prefix gcc@${{ inputs.compiler_version }})
|
||||
echo "PATH=$GCC_PREFIX/bin:$PATH" >> $GITHUB_ENV
|
||||
echo "CC=$GCC_PREFIX/bin/gcc-${{ inputs.compiler_version }}" >> $GITHUB_ENV
|
||||
|
|
@ -139,7 +139,6 @@ jobs:
|
|||
run: |
|
||||
sudo apt-get update && sudo apt-get install --assume-yes --no-install-recommends --quiet \
|
||||
binutils-dev \
|
||||
libdwarf-dev \
|
||||
libluajit-5.1-dev \
|
||||
libmariadb-dev-compat \
|
||||
libssl-dev \
|
||||
|
|
@ -243,15 +242,6 @@ jobs:
|
|||
xi_*
|
||||
tracy.tar.gz
|
||||
|
||||
- name: Remove exes from build cache
|
||||
if: ${{ inputs.save_cache && env.SKIP_BUILD != 'true' && steps.restore_build.outputs.cache-hit != 'true' }}
|
||||
run: |
|
||||
rm -f build/src/login/xi_connect*
|
||||
rm -f build/src/map/xi_map*
|
||||
rm -f build/src/search/xi_search*
|
||||
rm -f build/src/test/xi_test*
|
||||
rm -f build/src/world/xi_world*
|
||||
|
||||
- name: Cache build
|
||||
if: ${{ inputs.save_cache && env.SKIP_BUILD != 'true' && steps.restore_build.outputs.cache-hit != 'true' }}
|
||||
uses: actions/cache/save@v5
|
||||
|
|
|
|||
3
.github/workflows/runner_test.yml
vendored
3
.github/workflows/runner_test.yml
vendored
|
|
@ -80,7 +80,6 @@ jobs:
|
|||
sudo apt-get update && sudo apt-get install --assume-yes --no-install-recommends --quiet \
|
||||
binutils \
|
||||
git \
|
||||
libdwarf1 \
|
||||
libmariadb-dev-compat \
|
||||
libzmq5 \
|
||||
lua5.1 \
|
||||
|
|
@ -168,7 +167,7 @@ jobs:
|
|||
if: ${{ inputs.xi_test }}
|
||||
id: xi_test
|
||||
continue-on-error: true
|
||||
run: ./xi_test --keep-going --retry 5 --output tests.ctrf.json
|
||||
run: ./xi_test --keep-going --output tests.ctrf.json
|
||||
|
||||
- name: Publish Test Report
|
||||
if: ${{ !cancelled() && inputs.xi_test }}
|
||||
|
|
|
|||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -101,7 +101,7 @@ jobs:
|
|||
build_type: Release
|
||||
test_modules: false
|
||||
multi_process: true
|
||||
xi_test: true
|
||||
xi_test: ${{ !startsWith(matrix.runner, 'macos') }}
|
||||
startup_checks: true
|
||||
|
||||
Docker_Test:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
*.codegen.json
|
||||
*.codegen.lua
|
||||
|
||||
# YAML is formatted by tools/yaml/format.py
|
||||
*.yaml
|
||||
*.yml
|
||||
|
||||
build/
|
||||
build*/
|
||||
cmake-*/
|
||||
|
|
|
|||
11
.prettierrc
11
.prettierrc
|
|
@ -2,5 +2,14 @@
|
|||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"printWidth": 120,
|
||||
"endOfLine": "lf"
|
||||
"endOfLine": "lf",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.yaml", "**/*.yml"],
|
||||
"options": {
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
|
@ -13,7 +13,6 @@
|
|||
"jeff-hykin.better-cpp-syntax",
|
||||
"bierner.github-markdown-preview",
|
||||
"esbenp.prettier-vscode",
|
||||
"redhat.vscode-yaml",
|
||||
"jkillian.custom-local-formatters"
|
||||
"redhat.vscode-yaml"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
|
@ -356,19 +356,12 @@
|
|||
"editor.formatOnSave": true
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "jkillian.custom-local-formatters",
|
||||
"editor.formatOnSave": true
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"yaml.format.enable": false,
|
||||
"customLocalFormatters.formatters": [
|
||||
{
|
||||
"command": "python tools/yaml/format.py --stdin",
|
||||
"languages": ["yaml"]
|
||||
}
|
||||
],
|
||||
"files.associations": {
|
||||
"algorithm": "cpp",
|
||||
"any": "cpp",
|
||||
|
|
|
|||
|
|
@ -4,35 +4,15 @@ cmake_minimum_required(VERSION 3.25)
|
|||
cmake_policy(SET CMP0141 NEW)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
||||
|
||||
# On macOS, pin the deployment target to the host OS version (must happen before
|
||||
# project()). Without this, some compilers infer it from the Darwin kernel version
|
||||
# using the pre-macOS-26 numbering scheme (e.g. Homebrew LLVM 20 maps Darwin 25 to
|
||||
# "macOS 16.0" instead of 26), and every link against a Homebrew dylib stamped with
|
||||
# the real version warns:
|
||||
# ld: warning: building for macOS-16.0, but linking with dylib built for newer version 26.0
|
||||
# Overridable as usual via -DCMAKE_OSX_DEPLOYMENT_TARGET or MACOSX_DEPLOYMENT_TARGET.
|
||||
if(CMAKE_HOST_APPLE AND "${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "" AND "$ENV{MACOSX_DEPLOYMENT_TARGET}" STREQUAL "")
|
||||
execute_process(
|
||||
COMMAND sw_vers -productVersion
|
||||
OUTPUT_VARIABLE host_macos_version
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCH "^[0-9]+" host_macos_major "${host_macos_version}")
|
||||
if(host_macos_major)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "${host_macos_major}.0")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(server C CXX)
|
||||
|
||||
# https://cmake.org/cmake/help/latest/policy/CMP0069.html
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
|
||||
set(LINKER_LANGUAGE CXX)
|
||||
set(USE_FOLDERS ON)
|
||||
|
||||
|
|
@ -139,32 +119,22 @@ endif()
|
|||
|
||||
# Link this 'library' to set the c++ standard / compile-time options requested
|
||||
add_library(project_options INTERFACE)
|
||||
target_compile_features(project_options INTERFACE cxx_std_23)
|
||||
|
||||
# Windows-only preprocessor defines for our first-party code ONLY.
|
||||
if(WIN32)
|
||||
target_compile_definitions(project_options INTERFACE
|
||||
NOMINMAX
|
||||
WIN32_LEAN_AND_MEAN
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
target_compile_features(project_options INTERFACE cxx_std_20)
|
||||
|
||||
# Link this 'library' to use the warnings specified in CompilerWarnings.cmake
|
||||
add_library(project_warnings INTERFACE)
|
||||
set_project_warnings(project_warnings)
|
||||
|
||||
add_compile_definitions(
|
||||
# Globally define SOL_ALL_SAFETIES_ON so sol can be included anywhere.
|
||||
SOL_ALL_SAFETIES_ON=1
|
||||
# If SOL_NO_CHECK_NUMBER_PRECISION is defined, turns off number precision and integer
|
||||
# precision fitting when pushing numbers into sol.
|
||||
SOL_NO_CHECK_NUMBER_PRECISION=1
|
||||
SOL_DEFAULT_PASS_ON_ERROR=1
|
||||
SOL_PRINT_ERRORS=0
|
||||
SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG
|
||||
XI_CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
|
||||
XI_BUILD_TYPE="$<CONFIG>"
|
||||
# Globally define SOL_ALL_SAFETIES_ON so sol can be included anywhere
|
||||
# If SOL_NO_CHECK_NUMBER_PRECISION is defined, turns off number precision and integer
|
||||
# precision fitting when pushing numbers into sol
|
||||
# add_compile_definitions() comes with CMake 3.12
|
||||
add_definitions(
|
||||
-DSOL_ALL_SAFETIES_ON=1
|
||||
-DSOL_NO_CHECK_NUMBER_PRECISION=1
|
||||
-DSOL_DEFAULT_PASS_ON_ERROR=1
|
||||
-DSOL_PRINT_ERRORS=0
|
||||
-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG
|
||||
)
|
||||
|
||||
# For external libs
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ function(set_project_warnings project_name)
|
|||
CLANG_WARNINGS
|
||||
-Wno-nan-infinity-disabled # TODO: fmt triggers this, a combination of the fast-math flag and `isfinite`
|
||||
-Wunused-private-field # warn on unused private fields
|
||||
-Wno-nontrivial-memcall # recastnavigation memsets non-trivially-copyable types (e.g. dtMeshTile)
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
|
||||
if(${CMAKE_SOURCE_DIR} MATCHES " +")
|
||||
set(STRIPPED_PATH "")
|
||||
STRING(REGEX REPLACE " +" "_" STRIPPED_PATH "${CMAKE_SOURCE_DIR}")
|
||||
set(STRIPPED_PATH "")
|
||||
STRING(REGEX REPLACE " +" "_" STRIPPED_PATH "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
message(STATUS
|
||||
"Current path: ${CMAKE_SOURCE_DIR}\n"
|
||||
"Suggested path: ${STRIPPED_PATH}\n"
|
||||
"Your path contains spaces, this is not recommended.")
|
||||
message(STATUS
|
||||
"Current path: ${CMAKE_SOURCE_DIR}\n"
|
||||
"Suggested path: ${STRIPPED_PATH}\n"
|
||||
"Your path contains spaces, this is not recommended.")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
|
@ -33,15 +33,3 @@ set(libpath "lib${platform_suffix}")
|
|||
if(WIN32)
|
||||
set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# The modern Apple linker (ld_prime, Xcode 15+) warns when the same library
|
||||
# appears more than once on the link line. CMake's dependency propagation
|
||||
# legitimately repeats static libs (historically required by classic ld64),
|
||||
# so the warning is pure noise: silence it where the linker supports the flag.
|
||||
include(CheckLinkerFlag)
|
||||
check_linker_flag(CXX "-Wl,-no_warn_duplicate_libraries" LINKER_SUPPORTS_NO_WARN_DUPLICATE_LIBRARIES)
|
||||
if(LINKER_SUPPORTS_NO_WARN_DUPLICATE_LIBRARIES)
|
||||
add_link_options("-Wl,-no_warn_duplicate_libraries")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ if(MSVC)
|
|||
list(APPEND FLAGS_AND_DEFINES
|
||||
-D_CONSOLE
|
||||
-D_MBCS
|
||||
-DNOMINMAX
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
# TODO: This is being overwritten by /Ob0
|
||||
# /Ob2 # Inline Function Expansion
|
||||
|
|
@ -76,7 +78,7 @@ if(MSVC)
|
|||
)
|
||||
endif()
|
||||
|
||||
link_libraries(ws2_32 dbghelp shlwapi winmm shell32 user32)
|
||||
link_libraries(WS2_32 dbghelp Shlwapi)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
|
|
@ -115,25 +117,6 @@ function(set_target_output_directory target)
|
|||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# Under LTO the linker merges codegen objects into temp files and deletes after linking.
|
||||
# We need to preserve those for the next step!
|
||||
# -object_path_lto persists those codegen objects to a real, per-target directory so
|
||||
# dsymutil can gather their DWARF into the .dSYM.
|
||||
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
||||
set(lto_object_dir "${CMAKE_BINARY_DIR}/lto-objects/${target}")
|
||||
file(MAKE_DIRECTORY "${lto_object_dir}")
|
||||
target_link_options(${target} PRIVATE "-Wl,-object_path_lto,${lto_object_dir}")
|
||||
endif()
|
||||
|
||||
# dsymutil consolidates the DWARF into a self-contained .dSYM that travels with the
|
||||
# binary, and atos picks it up automatically.
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND "$<$<CONFIG:Debug,RelWithDebInfo>:dsymutil;$<TARGET_FILE:${target}>;-o;${CMAKE_SOURCE_DIR}/$<TARGET_FILE_NAME:${target}>.dSYM>"
|
||||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(disable_lto target)
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.allegiance
|
||||
|
||||
values:
|
||||
mob: 0
|
||||
player: 1
|
||||
san_doria: 2
|
||||
bastok: 3
|
||||
windurst: 4
|
||||
wyverns: 5
|
||||
griffons: 6
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.animation
|
||||
|
||||
values:
|
||||
none: 0
|
||||
attack: 1
|
||||
despawn: 2
|
||||
death: 3
|
||||
event: 4
|
||||
chocobo: 5
|
||||
fishing: 6
|
||||
open_door: 8
|
||||
close_door: 9
|
||||
elevator_up: 10
|
||||
elevator_down: 11
|
||||
fishing_npc: 32
|
||||
healing: 33
|
||||
fishing_fish: 38
|
||||
fishing_caught: 39
|
||||
fishing_rod_break: 40
|
||||
fishing_line_break: 41
|
||||
fishing_monster: 42
|
||||
fishing_stop: 43
|
||||
synth: 44
|
||||
sit: 47
|
||||
ranged: 48
|
||||
fishing_start: 50
|
||||
new_fishing_start: 56
|
||||
new_fishing_fish: 57
|
||||
new_fishing_caught: 58
|
||||
new_fishing_rod_break: 59
|
||||
new_fishing_line_break: 60
|
||||
new_fishing_monster: 61
|
||||
new_fishing_stop: 62
|
||||
# 63 through 73 are used with /sitchair
|
||||
sitchair_0: 63
|
||||
sitchair_1: 64
|
||||
sitchair_2: 65
|
||||
sitchair_3: 66
|
||||
sitchair_4: 67
|
||||
sitchair_5: 68
|
||||
sitchair_6: 69
|
||||
sitchair_7: 70
|
||||
sitchair_8: 71
|
||||
sitchair_9: 72
|
||||
sitchair_10: 73
|
||||
mount: 85
|
||||
trust: 90 # trust NPC spawn-in animation
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.attackType
|
||||
|
||||
values:
|
||||
none: 0
|
||||
physical: 1
|
||||
magical: 2
|
||||
ranged: 3
|
||||
breath: 4
|
||||
special: 5
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.behavior
|
||||
|
||||
values:
|
||||
none: 0x000
|
||||
no_despawn: 0x001 # mob does not despawn on death
|
||||
standback: 0x002 # mob will standback forever
|
||||
raisable: 0x004 # mob can be raised via Raise spells
|
||||
no_assist: 0x008 # mob can not be targeted by helpful magic from players (cure, protect, etc)
|
||||
aggro_ambush: 0x200 # mob aggroes by ambush
|
||||
no_turn: 0x400 # mob does not turn to face target
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.claimType
|
||||
|
||||
values:
|
||||
exclusive: 0 # Regular exclusive claim behavior. Only one entity and related group can attack.
|
||||
non_exclusive: 1 # Regular claim behavior but multiple unrelated entities can attack and compete for claim. Rewards distributed to last claiming entity.
|
||||
unclaimable: 2 # Mob cannot be claimed. Multiple unrelated entities can attack. Rewards will not be distributed.
|
||||
|
|
@ -7,17 +7,17 @@ meta:
|
|||
table: xi.damageType
|
||||
|
||||
values:
|
||||
none: 0
|
||||
piercing: 1
|
||||
slashing: 2
|
||||
blunt: 3
|
||||
none: 0
|
||||
piercing: 1
|
||||
slashing: 2
|
||||
blunt: 3
|
||||
hand_to_hand: 4
|
||||
elemental: 5
|
||||
fire: 6
|
||||
ice: 7
|
||||
wind: 8
|
||||
earth: 9
|
||||
thunder: 10
|
||||
water: 11
|
||||
light: 12
|
||||
dark: 13
|
||||
elemental: 5
|
||||
fire: 6
|
||||
ice: 7
|
||||
wind: 8
|
||||
earth: 9
|
||||
thunder: 10
|
||||
water: 11
|
||||
light: 12
|
||||
dark: 13
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.detects
|
||||
|
||||
values:
|
||||
none: 0x000
|
||||
sight: 0x001
|
||||
hearing: 0x002
|
||||
sight_and_hearing: 0x003
|
||||
lowhp: 0x004
|
||||
none1: 0x008
|
||||
none2: 0x010
|
||||
magic: 0x020
|
||||
weaponskill: 0x040
|
||||
jobability: 0x080
|
||||
scent: 0x100
|
||||
|
|
@ -7,26 +7,26 @@ meta:
|
|||
table: xi.ecosystem
|
||||
|
||||
values:
|
||||
unclassified: 0
|
||||
amorph: 1
|
||||
aquan: 2
|
||||
arcana: 3
|
||||
unclassified: 0
|
||||
amorph: 1
|
||||
aquan: 2
|
||||
arcana: 3
|
||||
archaic_machine: 4
|
||||
beast: 5
|
||||
beastmen: 6
|
||||
bird: 7
|
||||
demon: 8
|
||||
dragon: 9
|
||||
elemental: 10
|
||||
empty: 11
|
||||
humanoid: 12
|
||||
lizard: 13
|
||||
luminian: 14
|
||||
luminion: 15
|
||||
plantoid: 16
|
||||
supreme_beings: 17
|
||||
undead: 18
|
||||
vermin: 19
|
||||
voragean: 20
|
||||
structures: 21
|
||||
weapons: 22
|
||||
beast: 5
|
||||
beastmen: 6
|
||||
bird: 7
|
||||
demon: 8
|
||||
dragon: 9
|
||||
elemental: 10
|
||||
empty: 11
|
||||
humanoid: 12
|
||||
lizard: 13
|
||||
luminian: 14
|
||||
luminion: 15
|
||||
plantoid: 16
|
||||
supreme_beings: 17
|
||||
undead: 18
|
||||
vermin: 19
|
||||
voragean: 20
|
||||
structures: 21
|
||||
weapons: 22
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ meta:
|
|||
table: xi.effectOverwrite
|
||||
|
||||
values:
|
||||
equal_higher: 0 # only overwrite if equal or higher (tier, power)
|
||||
higher: 1 # only overwrite if higher (tier, power)
|
||||
never: 2 # never overwrite
|
||||
always: 3 # always overwrite no matter
|
||||
equal_higher: 0 # only overwrite if equal or higher (tier, power)
|
||||
higher: 1 # only overwrite if higher (tier, power)
|
||||
never: 2 # never overwrite
|
||||
always: 3 # always overwrite no matter
|
||||
ignore_duplicate: 4 # ignore dupes
|
||||
tier_higher: 5 # only overwrite if tier is higher (regardless of power)
|
||||
tier_higher: 5 # only overwrite if tier is higher (regardless of power)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ meta:
|
|||
table: xi.element
|
||||
|
||||
values:
|
||||
none: 0
|
||||
fire: 1
|
||||
ice: 2
|
||||
wind: 3
|
||||
earth: 4
|
||||
none: 0
|
||||
fire: 1
|
||||
ice: 2
|
||||
wind: 3
|
||||
earth: 4
|
||||
thunder: 5
|
||||
water: 6
|
||||
light: 7
|
||||
dark: 8
|
||||
water: 6
|
||||
light: 7
|
||||
dark: 8
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint32_t
|
||||
lua:
|
||||
table: xi.entityFlags
|
||||
|
||||
values:
|
||||
none: 0x000
|
||||
info_icon: 0x001 # (I) Icon next to name
|
||||
# TODO: Flags 0x002, 0x004 and 0x008 do different things for different entities.
|
||||
# : It isn't one-size-fits-all, and different combinations may do different things.
|
||||
# : It'll need to be researched more.
|
||||
# alt_appearance: 0x002
|
||||
hide_name: 0x008
|
||||
call_for_help: 0x020
|
||||
hide_model: 0x080
|
||||
hide_hp: 0x100
|
||||
untargetable: 0x800
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint32_t
|
||||
lua:
|
||||
table: xi.immunity
|
||||
|
||||
values:
|
||||
none: 0x00000000
|
||||
addle: 0x00000001
|
||||
gravity: 0x00000002
|
||||
bind: 0x00000004
|
||||
stun: 0x00000008
|
||||
silence: 0x00000010
|
||||
paralyze: 0x00000020
|
||||
blind: 0x00000040
|
||||
slow: 0x00000080
|
||||
poison: 0x00000100
|
||||
elegy: 0x00000200
|
||||
requiem: 0x00000400
|
||||
light_sleep: 0x00000800
|
||||
dark_sleep: 0x00001000
|
||||
aspir: 0x00002000
|
||||
terror: 0x00004000
|
||||
dispel: 0x00008000
|
||||
petrify: 0x00010000
|
||||
plague: 0x00020000
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
case: screaming
|
||||
lua:
|
||||
table: xi.job
|
||||
|
||||
values:
|
||||
none: 0
|
||||
war: 1
|
||||
mnk: 2
|
||||
whm: 3
|
||||
blm: 4
|
||||
rdm: 5
|
||||
thf: 6
|
||||
pld: 7
|
||||
drk: 8
|
||||
bst: 9
|
||||
brd: 10
|
||||
rng: 11
|
||||
sam: 12
|
||||
nin: 13
|
||||
drg: 14
|
||||
smn: 15
|
||||
blu: 16
|
||||
cor: 17
|
||||
pup: 18
|
||||
dnc: 19
|
||||
sch: 20
|
||||
geo: 21
|
||||
run: 22
|
||||
mon: 23 # NOTE: MON is not a full job
|
||||
|
|
@ -7,69 +7,67 @@ meta:
|
|||
table: xi.latent
|
||||
|
||||
values:
|
||||
hp_under_percent: 0 # hp less than or equal to % - PARAM: HP PERCENT
|
||||
hp_over_percent: 1 # hp more than % - PARAM: HP PERCENT
|
||||
hp_under_tp_under_100: 2 # hp less than or equal to %, tp under 100 - PARAM: HP PERCENT
|
||||
hp_over_tp_under_100: 3 # hp more than %, tp over 100 - PARAM: HP PERCENT
|
||||
mp_under_percent: 4 # mp less than or equal to % - PARAM: MP PERCENT
|
||||
mp_under: 5 # mp less than # - PARAM: MP #
|
||||
tp_under: 6 # tp under # and during WS - PARAM: TP VALUE
|
||||
tp_over: 7 # tp over # - PARAM: TP VALUE
|
||||
subjob: 8 # subjob - PARAM: JOBTYPE
|
||||
pet_id: 9 # pettype - PARAM: PETID
|
||||
weapon_drawn: 10 # weapon drawn
|
||||
weapon_sheathed: 11 # weapon sheathed
|
||||
signet_bonus: 12 # While in conquest region and engaged to an even match or less target
|
||||
status_effect_active: 13 # status effect on player - PARAM: EFFECTID
|
||||
no_food_active: 14 # no food effects active on player
|
||||
party_members: 15 # party size # - PARAM: # OF MEMBERS
|
||||
party_members_in_zone: 16 # party size # and members in zone - PARAM: # OF MEMBERS
|
||||
sanction_regen_bonus: 17 # While in besieged region and HP is less than PARAM%
|
||||
hp_under_percent: 0 # hp less than or equal to % - PARAM: HP PERCENT
|
||||
hp_over_percent: 1 # hp more than % - PARAM: HP PERCENT
|
||||
hp_under_tp_under_100: 2 # hp less than or equal to %, tp under 100 - PARAM: HP PERCENT
|
||||
hp_over_tp_under_100: 3 # hp more than %, tp over 100 - PARAM: HP PERCENT
|
||||
mp_under_percent: 4 # mp less than or equal to % - PARAM: MP PERCENT
|
||||
mp_under: 5 # mp less than # - PARAM: MP #
|
||||
tp_under: 6 # tp under # and during WS - PARAM: TP VALUE
|
||||
tp_over: 7 # tp over # - PARAM: TP VALUE
|
||||
subjob: 8 # subjob - PARAM: JOBTYPE
|
||||
pet_id: 9 # pettype - PARAM: PETID
|
||||
weapon_drawn: 10 # weapon drawn
|
||||
weapon_sheathed: 11 # weapon sheathed
|
||||
signet_bonus: 12 # While in conquest region and engaged to an even match or less target
|
||||
status_effect_active: 13 # status effect on player - PARAM: EFFECTID
|
||||
no_food_active: 14 # no food effects active on player
|
||||
party_members: 15 # party size # - PARAM: # OF MEMBERS
|
||||
party_members_in_zone: 16 # party size # and members in zone - PARAM: # OF MEMBERS
|
||||
sanction_regen_bonus: 17 # While in besieged region and HP is less than PARAM%
|
||||
sanction_refresh_bonus: 18 # While in besieged region and MP is less than PARAM%
|
||||
sigil_regen_bonus: 19 # While in campaign region and HP is less than PARAM%
|
||||
sigil_refresh_bonus: 20 # While in campaign region and MP is less than PARAM%
|
||||
avatar_in_party: 21 # party has a specific avatar - PARAM: same as globals/pets.lua (21 for any avatar)
|
||||
job_in_party: 22 # party has job - PARAM: JOBTYPE
|
||||
zone: 23 # in zone - PARAM: zoneid
|
||||
synth_trainee: 24 # synth skill under 40 + no support: PARAM: 48: FISH, 49: WOOD, 50: SMITH, 51: GOLDSMITH, 52: CLOTH, 53: LEATHER, 54: BONE, 55: ALCHEMY, 56: COOKING
|
||||
song_roll_active: 25 # any song or roll active
|
||||
time_of_day: 26 # PARAM: 0: DAYTIME 1: NIGHTTIME 2: DUSK-DAWN
|
||||
hour_of_day: 27 # PARAM: 1: NEW DAY, 2: DAWN, 3: DAY, 4: DUSK, 5: EVENING, 6: DEAD OF NIGHT
|
||||
firesday: 28
|
||||
earthsday: 29
|
||||
watersday: 30
|
||||
windsday: 31
|
||||
darksday: 32
|
||||
iceday: 34
|
||||
lightningsday: 35
|
||||
lightsday: 36
|
||||
moon_phase: 37 # PARAM: 0: New Moon, 1: Waxing Crescent, 2: First Quarter, 3: Waxing Gibbous, 4: Full Moon, 5: Waning Gibbous, 6: Last Quarter, 7: Waning Crescent
|
||||
job_multiple: 38 # PARAM: 0: ODD, 2: EVEN, 3-X: DIVISOR
|
||||
job_multiple_at_night: 39 # PARAM: 0: ODD, 2: EVEN, 3-X: DIVISOR
|
||||
equipped_in_slot: 40 # When item is equipped in the specified slot (e.g. Dweomer Knife, Erlking's Sword, etc.) PARAM: slotID
|
||||
during_ws: 41 # During WS
|
||||
weather_condition: 42 # See Weather.h for WEATHER enum
|
||||
weapon_drawn_hp_under: 43 # PARAM: HP PERCENT
|
||||
nation_citizen: 44 # Triggered by player being citizen of nation matching param: 0 San d'Oria, 1 Bastok, 2 Windurst
|
||||
mp_under_visible_gear: 45 # mp less than or equal to %, calculated using MP bonuses from visible gear only
|
||||
hp_over_visible_gear: 46 # hp more than or equal to %, calculated using HP bonuses from visible gear only
|
||||
weapon_broken: 47
|
||||
in_dynamis: 48
|
||||
food_active: 49 # food effect (foodId) active - PARAM: FOOD ITEMID
|
||||
job_level_below: 50 # PARAM: level
|
||||
job_level_above: 51 # PARAM: level
|
||||
weather_element: 52 # PARAM: 0: NONE, 1: FIRE, 2: ICE, 3: WIND 4: EARTH, 5: THUNDER, 6: WATER, 7: LIGHT, 8: DARK
|
||||
nation_control: 53 # checks if player region is under nation's control - PARAM: 0: Under own nation's control, 1: Outside own nation's control
|
||||
zone_home_nation: 54 # in zone and citizen of nation (aketons)
|
||||
mp_over: 55 # mp greater than # - PARAM: MP #
|
||||
weapon_drawn_mp_over: 56 # while weapon is drawn and mp greater than # - PARAM: MP #
|
||||
eleven_roll_active: 57 # corsair roll of 11 active
|
||||
in_assault: 58 # is in an Instance battle in a TOAU zone
|
||||
vs_ecosystem: 59 # Vs. Specific Ecosystem ID (e.g. Vs. Plantoid: Accuracy+3)
|
||||
vs_species: 60 # Vs. Specific Species ID (e.g. Vs. Korrigan: Accuracy+3)
|
||||
vs_family: 61 # Vs. Specific Family ID (e.g. Vs. Mandragora: Accuracy+3)
|
||||
mainjob: 62 # mainjob - PARAM: JOBTYPE
|
||||
in_adoulin: 63
|
||||
in_garrison: 64 # while in an active Garrison
|
||||
sanction_food_bonus: 65 # While in besieged region
|
||||
sigil_food_bonus: 66 # While in campaign region
|
||||
sigil_regen_bonus: 19 # While in campaign region and HP is less than PARAM%
|
||||
sigil_refresh_bonus: 20 # While in campaign region and MP is less than PARAM%
|
||||
avatar_in_party: 21 # party has a specific avatar - PARAM: same as globals/pets.lua (21 for any avatar)
|
||||
job_in_party: 22 # party has job - PARAM: JOBTYPE
|
||||
zone: 23 # in zone - PARAM: zoneid
|
||||
synth_trainee: 24 # synth skill under 40 + no support: PARAM: 48: FISH, 49: WOOD, 50: SMITH, 51: GOLDSMITH, 52: CLOTH, 53: LEATHER, 54: BONE, 55: ALCHEMY, 56: COOKING
|
||||
song_roll_active: 25 # any song or roll active
|
||||
time_of_day: 26 # PARAM: 0: DAYTIME 1: NIGHTTIME 2: DUSK-DAWN
|
||||
hour_of_day: 27 # PARAM: 1: NEW DAY, 2: DAWN, 3: DAY, 4: DUSK, 5: EVENING, 6: DEAD OF NIGHT
|
||||
firesday: 28
|
||||
earthsday: 29
|
||||
watersday: 30
|
||||
windsday: 31
|
||||
darksday: 32
|
||||
iceday: 34
|
||||
lightningsday: 35
|
||||
lightsday: 36
|
||||
moon_phase: 37 # PARAM: 0: New Moon, 1: Waxing Crescent, 2: First Quarter, 3: Waxing Gibbous, 4: Full Moon, 5: Waning Gibbous, 6: Last Quarter, 7: Waning Crescent
|
||||
job_multiple: 38 # PARAM: 0: ODD, 2: EVEN, 3-X: DIVISOR
|
||||
job_multiple_at_night: 39 # PARAM: 0: ODD, 2: EVEN, 3-X: DIVISOR
|
||||
equipped_in_slot: 40 # When item is equipped in the specified slot (e.g. Dweomer Knife, Erlking's Sword, etc.) PARAM: slotID
|
||||
during_ws: 41 # During WS
|
||||
weather_condition: 42 # See Weather.h for WEATHER enum
|
||||
weapon_drawn_hp_under: 43 # PARAM: HP PERCENT
|
||||
nation_citizen: 44 # Triggered by player being citizen of nation matching param: 0 San d'Oria, 1 Bastok, 2 Windurst
|
||||
mp_under_visible_gear: 45 # mp less than or equal to %, calculated using MP bonuses from visible gear only
|
||||
hp_over_visible_gear: 46 # hp more than or equal to %, calculated using HP bonuses from visible gear only
|
||||
weapon_broken: 47
|
||||
in_dynamis: 48
|
||||
food_active: 49 # food effect (foodId) active - PARAM: FOOD ITEMID
|
||||
job_level_below: 50 # PARAM: level
|
||||
job_level_above: 51 # PARAM: level
|
||||
weather_element: 52 # PARAM: 0: NONE, 1: FIRE, 2: ICE, 3: WIND 4: EARTH, 5: THUNDER, 6: WATER, 7: LIGHT, 8: DARK
|
||||
nation_control: 53 # checks if player region is under nation's control - PARAM: 0: Under own nation's control, 1: Outside own nation's control
|
||||
zone_home_nation: 54 # in zone and citizen of nation (aketons)
|
||||
mp_over: 55 # mp greater than # - PARAM: MP #
|
||||
weapon_drawn_mp_over: 56 # while weapon is drawn and mp greater than # - PARAM: MP #
|
||||
eleven_roll_active: 57 # corsair roll of 11 active
|
||||
in_assault: 58 # is in an Instance battle in a TOAU zone
|
||||
vs_ecosystem: 59 # Vs. Specific Ecosystem ID (e.g. Vs. Plantoid: Accuracy+3)
|
||||
vs_species: 60 # Vs. Specific Species ID (e.g. Vs. Korrigan: Accuracy+3)
|
||||
vs_family: 61 # Vs. Specific Family ID (e.g. Vs. Mandragora: Accuracy+3)
|
||||
mainjob: 62 # mainjob - PARAM: JOBTYPE
|
||||
in_adoulin: 63
|
||||
in_garrison: 64 # while in an active Garrison
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.mobMod
|
||||
|
||||
values:
|
||||
none: 0
|
||||
gil_min: 1 # minimum gil drop -- spawn mod only
|
||||
gil_max: 2 # maximum gil drop -- spawn mod only
|
||||
mp_base: 3 # Give mob mp. Used for mobs that are not mages, wyverns, avatars
|
||||
sight_range: 4 # sight range
|
||||
sound_range: 5 # sound range
|
||||
buff_chance: 6 # % chance to buff (combat only)
|
||||
ga_chance: 7 # % chance to use -ga spell
|
||||
heal_chance: 8 # % chance to use heal
|
||||
hp_heal_chance: 9 # can cast cures below this HP %
|
||||
sublink: 10 # Sub link group. Enables mobs from different families to link if they share a SUBLINK value.
|
||||
link_radius: 11 # link radius
|
||||
sees_through_illusion: 12 # Mob can see through the Illusion effect that grants effects similar to Sneak & Invisible without this mod and allows aggro (see Viscious Liquid in mamook)
|
||||
severe_spell_chance: 13 # % chance to use a severe spell like death or impact
|
||||
skill_list: 14 # uses given mob skill list
|
||||
mug_gil: 15 # amount gil carried for mugging
|
||||
detection: 16 # Overrides mob family's detection method. In order to set to override to none an unused bit must be set such as xi::Detects::None1.
|
||||
no_despawn: 17 # do not despawn when too far from spawn. Gob Diggers have this.
|
||||
var: 18 # temp var for whatever. Gets cleared on spawn
|
||||
can_shield_block: 19 # toggle shield use for mobs without physical shields (trusts)
|
||||
no_h2h_penalty: 20 # Disables H2H penalty in base damage calculation when set to non-zero
|
||||
pet_spell_list: 21 # set pet spell list
|
||||
na_chance: 22 # % chance to cast -na
|
||||
immunity: 23 # immune to set status effects. This only works from the db, not scripts
|
||||
gradual_rage: 24 # (!) TODO: NOT YET IMPLEMENTED -- gradually rages
|
||||
build_resist: 25 # (!) TODO: NOT YET IMPLEMENTED -- builds resistance to given effects
|
||||
superlink: 26 # super link group. Only use this in scripts! Must be defined in onMobInitialize if relevant mobs are different families
|
||||
spell_list: 27 # set spell list
|
||||
exp_bonus: 28 # bonus exp (bonus / 100) negative values reduce exp.
|
||||
assist: 29 # mobs will assist me
|
||||
special_skill: 30 # give special skill
|
||||
roam_distance: 31 # distance allowed to roam from spawn
|
||||
dont_roam_home: 32 # Allow mobs to roam any distance from spawn. Useful for mobs with scripted roaming behavior.
|
||||
special_cool: 33 # cool down for special
|
||||
magic_cool: 34 # cool down for magic
|
||||
standback_cool: 35 # cool down time for standing back (casting spell while not in attack range)
|
||||
roam_cool: 36 # cool down time in seconds after roaming
|
||||
always_aggro: 37 # aggro regardless of level. Spheroids
|
||||
no_drops: 38 # If set monster cannot drop any items, not even seals.
|
||||
share_pos: 39 # share a pos with another mob (eald'narche exoplates)
|
||||
teleport_cd: 40 # cooldown for teleport abilities (tarutaru AA, angra mainyu, eald'narche)
|
||||
teleport_start: 41 # mobskill ID to begin teleport
|
||||
teleport_end: 42 # mobskill ID to end teleport
|
||||
teleport_type: 43 # teleport type - 1: on cooldown, 2 - to close distance
|
||||
dual_wield: 44 # enables a mob to use their offhand in attacks
|
||||
add_effect: 45 # enables additional effect script to process on mobs attacks
|
||||
auto_spikes: 46 # enables additional effect script to process when mob is attacked
|
||||
spawn_leash: 47 # forces a mob to not move farther from its spawn than its leash distance
|
||||
share_target: 48 # mob always targets same target as ID in this var
|
||||
check_as_nm: 49 # If set , mob will check as a NM
|
||||
roam_reset_facing: 50 # Resume facing the default spawn rotation after roaming home.
|
||||
roam_turns: 51 # Maximum amount of turns during a roam
|
||||
roam_rate: 52 # Roaming frequency. roam_cool - rand(roam_cool / (roam_rate / 10))
|
||||
behavior: 53 # Add behaviors to mob
|
||||
gil_bonus: 54 # Allow mob to drop gil. Multiplier to gil dropped by mob (bonus / 100) * total
|
||||
idle_despawn: 55 # Time (in seconds) to despawn after being idle
|
||||
hp_standback: 56 # mob will always standback with hp % higher to value
|
||||
magic_delay: 57 # Amount of seconds mob waits before casting first spell
|
||||
special_delay: 58 # Amount of seconds mob waits before using first special
|
||||
base_damage_modifier: 59 # Add a flat modifer mob a mob's base damage. This is subject to multiplication by MOBMOD_BASE_DAMAGE_MULTIPLIER.
|
||||
spawn_animationsub: 60 # reset animationsub to this on spawn
|
||||
hp_scale: 61 # Scale the mobs max HP. ( hp_scale / 100 ) * maxhp
|
||||
no_standback: 62 # Mob will never standback
|
||||
attack_skill_list: 63 # skill list to use in place of regular attacks
|
||||
charmable: 64 # mob is charmable
|
||||
no_move: 65 # Mob will not be able to move
|
||||
multi_hit: 66 # Mob will have as many swings as defined.
|
||||
no_aggro: 67 # If set, mob cannot aggro until unset.
|
||||
alli_hate: 68 # Range around target to add alliance member to enmity list.
|
||||
no_link: 69 # If set, mob cannot link until unset.
|
||||
no_rest: 70 # Mob cannot regain hp (e.g. re-burrowing antlions during ENM).
|
||||
leader: 71 # Used for mob following. Positive number is how many followers a leader has. A negative number is the distance from this mob ID to the leader ID.
|
||||
magic_range: 72 # magic aggro range
|
||||
target_distance_offset: 73 # Adjusts how close a mob will move to it's target. 12 = 1.2 yalm. Positive values to go closer, negative farther.
|
||||
one_way_linking: 74 # Will link with other mobs in its party (typically the same mob family) while roaming, but will not let others link with it once engaged
|
||||
can_parry: 75 # Check if a mob is allowed to have parry rank (Rank Value 1-5)
|
||||
no_widescan: 76 # Disables widescan for a specific mob
|
||||
trust_distance: 77 # TRUSTS ONLY: Set movement type/distance. See trust.lua for details.
|
||||
standback_range: 78 # Applies a specific standback range for the mob
|
||||
cannot_guard: 79 # Check if the mob does not guard(despite being a MNK or PUP mob)
|
||||
skip_allegiance_check: 80 # Skip the allegiance check for valid target (allows for example a mob to cast a TARGET_ENEMY spell on itself)
|
||||
ability_response: 81 # Mob can respond to player ability use with onPlayerAbilityUse()
|
||||
run_speed_mult: 82 # Multiplier for the speed of a mob while running (generally when the target is out of range) 100 = 1.00x
|
||||
claim_type: 83 # Changes the claim behavior of the mob. See xi::ClaimType enum.
|
||||
no_spell_cost: 84 # Mob does not use MP when casting spells
|
||||
astral_pet_offset: 85 # If non-zero, defines the offset from main mob's ID for astral flow (if zero, will assume offset of 2)
|
||||
base_damage_multiplier: 86 # Multiplies the mob's base damage. Example: 150 = x1.5. MOBMOD_DAMAGE_OFFSET/MOBMOD_RANGED_DAMAGE_OFFSET are not subject to multiplication.
|
||||
damage_offset: 87 # Adds or subtracts the mob's base damage offset.
|
||||
ranged_damage_offset: 88 # Adds or subtracts the mob's ranged base damage offset.
|
||||
avatar_petid: 89 # A value from xi.petId to select model/ability from when owner uses astral flow
|
||||
avatar_astral_delay: 90 # Number of milliseconds to delay AF after avatar spawn
|
||||
h2h_single_swing: 91 # Mob will have only one swing per attack even as MNK with H2H skill
|
||||
aoe_hit_all: 92 # Mob AoE can hit any player regardless of enmity
|
||||
ranged_attack_range: 93 # Max range for ranged auto attacks. Mob will move closer if target is beyond this range.
|
||||
follow_leash_range: 94 # Distance the leader can walk before their followers start moving. Applied to followers.
|
||||
follow_stop_range: 95 # Distance the followers attempt to stop at once their leader stops moving. Applied to followers.
|
||||
trust_shield_size: 96 # TRUSTS ONLY: Set the size of the mob's shield. 3 = Default size, only used for trusts that use shields.
|
||||
bodyguard: 97 # Charmed mob defends its master similar to an avatar. (Maiden's Virelai)
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.mobType
|
||||
|
||||
values:
|
||||
normal: 0x00
|
||||
unused: 0x01 # available for use
|
||||
notorious: 0x02
|
||||
fished: 0x04
|
||||
called: 0x08
|
||||
battlefield: 0x10
|
||||
event: 0x20
|
||||
1275
data/enums/mod.yaml
1275
data/enums/mod.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.nameVis
|
||||
|
||||
values:
|
||||
none: 0x00
|
||||
icon: 0x01 # (I) Icon next to name
|
||||
hide_name: 0x08
|
||||
ghost_phase: 0x80
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.roamFlag
|
||||
|
||||
values:
|
||||
none: 0x000
|
||||
none0: 0x001
|
||||
none1: 0x002
|
||||
none2: 0x004
|
||||
none3: 0x008
|
||||
none4: 0x010
|
||||
none5: 0x020
|
||||
worm: 0x040 # pop up and down when moving
|
||||
ambush: 0x080 # stays hidden until someone comes close (antlion)
|
||||
scripted: 0x100 # calls lua method for roaming logic
|
||||
ignore: 0x200 # ignore all hate, except linking hate
|
||||
stealth: 0x400 # stays name hidden and untargetable until someone comes close (chigoe)
|
||||
follow: 0x800 # follows a player when sighted for a little while
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.skill
|
||||
|
||||
values:
|
||||
# Combat Skills
|
||||
none: 0
|
||||
hand_to_hand: 1
|
||||
dagger: 2
|
||||
sword: 3
|
||||
great_sword: 4
|
||||
axe: 5
|
||||
great_axe: 6
|
||||
scythe: 7
|
||||
polearm: 8
|
||||
katana: 9
|
||||
great_katana: 10
|
||||
club: 11
|
||||
staff: 12
|
||||
# 13-21 unused
|
||||
automaton_melee: 22
|
||||
automaton_ranged: 23
|
||||
automaton_magic: 24
|
||||
archery: 25
|
||||
marksmanship: 26
|
||||
throwing: 27
|
||||
# Defensive Skills
|
||||
guard: 28
|
||||
evasion: 29
|
||||
shield: 30
|
||||
parry: 31
|
||||
# Magic Skills
|
||||
divine_magic: 32
|
||||
healing_magic: 33
|
||||
enhancing_magic: 34
|
||||
enfeebling_magic: 35
|
||||
elemental_magic: 36
|
||||
dark_magic: 37
|
||||
summoning_magic: 38
|
||||
ninjutsu: 39
|
||||
singing: 40
|
||||
string_instrument: 41
|
||||
wind_instrument: 42
|
||||
blue_magic: 43
|
||||
geomancy: 44
|
||||
handbell: 45
|
||||
# 46-47 unused
|
||||
# Crafting Skills
|
||||
fishing: 48
|
||||
woodworking: 49
|
||||
smithing: 50
|
||||
goldsmithing: 51
|
||||
clothcraft: 52
|
||||
leathercraft: 53
|
||||
bonecraft: 54
|
||||
alchemy: 55
|
||||
cooking: 56
|
||||
synergy: 57
|
||||
# Other Skills
|
||||
rid: 58
|
||||
dig: 59
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.spawnAnimation
|
||||
|
||||
values:
|
||||
normal: 0
|
||||
special: 1
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.spawnType
|
||||
|
||||
values:
|
||||
normal: 0x00 # 00:00-24:00
|
||||
at_night: 0x01 # 20:00-04:00
|
||||
at_evening: 0x02 # 18:00-06:00
|
||||
weather: 0x04
|
||||
fog: 0x08 # 02:00-07:00
|
||||
moonphase: 0x10
|
||||
lottery: 0x20
|
||||
windowed: 0x40
|
||||
scripted: 0x80 # scripted spawn
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint8_t
|
||||
lua:
|
||||
table: xi.status
|
||||
|
||||
values:
|
||||
normal: 0
|
||||
update: 1
|
||||
disappear: 2
|
||||
invisible: 3
|
||||
status_4: 4
|
||||
cutscene_only: 6
|
||||
status_18: 18
|
||||
shutdown: 20
|
||||
|
|
@ -8,35 +8,35 @@ meta:
|
|||
table: xi.effectFlag
|
||||
|
||||
values:
|
||||
none: 0x00000000
|
||||
dispelable: 0x00000001
|
||||
erasable: 0x00000002
|
||||
attack: 0x00000004
|
||||
empathy: 0x00000008
|
||||
damage: 0x00000010
|
||||
death: 0x00000020
|
||||
magic_begin: 0x00000040
|
||||
magic_end: 0x00000080
|
||||
on_zone: 0x00000100
|
||||
none: 0x00000000
|
||||
dispelable: 0x00000001
|
||||
erasable: 0x00000002
|
||||
attack: 0x00000004
|
||||
empathy: 0x00000008
|
||||
damage: 0x00000010
|
||||
death: 0x00000020
|
||||
magic_begin: 0x00000040
|
||||
magic_end: 0x00000080
|
||||
on_zone: 0x00000100
|
||||
no_loss_message: 0x00000200
|
||||
invisible: 0x00000400
|
||||
detectable: 0x00000800
|
||||
no_rest: 0x00001000
|
||||
prevent_action: 0x00002000
|
||||
waltzable: 0x00004000
|
||||
food: 0x00008000
|
||||
song: 0x00010000
|
||||
roll: 0x00020000
|
||||
synth_support: 0x00040000
|
||||
confrontation: 0x00080000
|
||||
logout: 0x00100000
|
||||
bloodpact: 0x00200000
|
||||
on_jobchange: 0x00400000
|
||||
no_cancel: 0x00800000
|
||||
influence: 0x01000000
|
||||
offline_tick: 0x02000000
|
||||
aura: 0x04000000
|
||||
hide_timer: 0x08000000
|
||||
on_zone_pathos: 0x10000000
|
||||
invisible: 0x00000400
|
||||
detectable: 0x00000800
|
||||
no_rest: 0x00001000
|
||||
prevent_action: 0x00002000
|
||||
waltzable: 0x00004000
|
||||
food: 0x00008000
|
||||
song: 0x00010000
|
||||
roll: 0x00020000
|
||||
synth_support: 0x00040000
|
||||
confrontation: 0x00080000
|
||||
logout: 0x00100000
|
||||
bloodpact: 0x00200000
|
||||
on_jobchange: 0x00400000
|
||||
no_cancel: 0x00800000
|
||||
influence: 0x01000000
|
||||
offline_tick: 0x02000000
|
||||
aura: 0x04000000
|
||||
hide_timer: 0x08000000
|
||||
on_zone_pathos: 0x10000000
|
||||
always_expiring: 0x20000000
|
||||
on_attack: 0x40000000
|
||||
on_attack: 0x40000000
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.weather
|
||||
|
||||
values:
|
||||
none: 0
|
||||
sunshine: 1
|
||||
clouds: 2
|
||||
fog: 3
|
||||
hot_spell: 4
|
||||
heat_wave: 5
|
||||
rain: 6
|
||||
squall: 7
|
||||
dust_storm: 8
|
||||
sand_storm: 9
|
||||
wind: 10
|
||||
gales: 11
|
||||
snow: 12
|
||||
blizzards: 13
|
||||
thunder: 14
|
||||
thunderstorms: 15
|
||||
auroras: 16
|
||||
stellar_glare: 17
|
||||
gloom: 18
|
||||
darkness: 19
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.zoneMisc
|
||||
|
||||
values:
|
||||
none: 0x0000 # Able to be used in any area
|
||||
escape: 0x0001 # Ability to use Escape Spell
|
||||
fellow: 0x0002 # Ability to summon Fellow NPC
|
||||
mount: 0x0004 # Ability to use Chocobos and mounts
|
||||
mazurka: 0x0008 # Ability to use Mazurka Spell
|
||||
tractor: 0x0010 # Ability to use Tractor Spell
|
||||
mogmenu: 0x0020 # Ability to communicate with Nomad Moogle (menu access mog house)
|
||||
costume: 0x0040 # Ability to use a Costumes
|
||||
pet: 0x0080 # Ability to summon Pets
|
||||
treasure: 0x0100 # Presence in the global zone TreasurePool
|
||||
auction_house: 0x0200 # Ability to use the auction house
|
||||
yell: 0x0400 # Send and receive /yell commands
|
||||
trust: 0x0800 # Ability to summon Trust NPC
|
||||
los_player_block: 0x1000 # Players can't use magic/JAs through walls if this is set
|
||||
los_off: 0x2000 # Zone should not have LoS checks
|
||||
assist: 0x4000 # Send and receive /assiste, /assistj commands
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# yaml-language-server: $schema=../schemas/enums/_enum.schema.json
|
||||
|
||||
meta:
|
||||
flags: true
|
||||
cpp:
|
||||
underlying: uint16_t
|
||||
lua:
|
||||
table: xi.zoneType
|
||||
|
||||
values:
|
||||
unknown: 0x0000
|
||||
city: 0x0001
|
||||
outdoors: 0x0002
|
||||
dungeon: 0x0004
|
||||
signet: 0x0008
|
||||
sanction: 0x0010
|
||||
sigil: 0x0020
|
||||
ionis: 0x0040
|
||||
dynamis: 0x0080
|
||||
instanced: 0x0100
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -12,7 +12,6 @@ apk --update-cache add \
|
|||
bash \
|
||||
binutils \
|
||||
git \
|
||||
libdwarf \
|
||||
lua5.1-dev \
|
||||
luajit \
|
||||
mariadb-client \
|
||||
|
|
@ -66,15 +65,13 @@ apk --update-cache add \
|
|||
ccache \
|
||||
cmake \
|
||||
g++ \
|
||||
libdwarf-dev \
|
||||
linux-headers \
|
||||
luajit-dev \
|
||||
make \
|
||||
mariadb-dev \
|
||||
ninja-build \
|
||||
ninja-is-really-ninja \
|
||||
openssl-dev \
|
||||
python3-dev \
|
||||
samurai \
|
||||
zeromq-dev \
|
||||
zlib-dev \
|
||||
zstd-dev
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ apt-get update && apt-get install --assume-yes --no-install-recommends --quiet \
|
|||
binutils \
|
||||
ca-certificates \
|
||||
git \
|
||||
libdwarf1 \
|
||||
libzmq5 \
|
||||
lua5.1 \
|
||||
luajit \
|
||||
|
|
@ -75,14 +74,12 @@ apt-get update && apt-get install --assume-yes --no-install-recommends --quiet \
|
|||
ccache \
|
||||
cmake \
|
||||
g++-$GCC_VERSION \
|
||||
libdwarf-dev \
|
||||
libluajit-5.1-dev \
|
||||
libmariadb-dev-compat \
|
||||
libssl-dev \
|
||||
libzmq3-dev \
|
||||
make \
|
||||
ninja-build \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
python3-venv \
|
||||
zlib1g-dev \
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
# add_subdirectory(zmq) # Handled globally
|
||||
# add_subdirectory(openssl) # Handled globally
|
||||
add_subdirectory(concurrentqueue)
|
||||
add_subdirectory(SPSCQueue)
|
||||
add_subdirectory(sol)
|
||||
|
||||
# CPM Modules
|
||||
|
|
@ -299,48 +298,10 @@ CPMAddPackage(
|
|||
SYSTEM ON
|
||||
) # defines: unordered_dense::unordered_dense (aliased to FlatHashMap, see src/common/flat_hash_map.h)
|
||||
|
||||
# TODO: std::move_only_function lands in C++23, but libc++ (macOS) has not implemented
|
||||
# : it yet. Remove this once all compilers for all platforms implement.
|
||||
CPMAddPackage(
|
||||
NAME function2
|
||||
GITHUB_REPOSITORY Naios/function2
|
||||
GIT_TAG 4.2.4
|
||||
SYSTEM ON
|
||||
) # defines: function2 (aliased to Fn, see src/common/types/fn.h)
|
||||
|
||||
# How cpptrace turns a crash address into function + file:line, per platform:
|
||||
set(CPPTRACE_SYMBOL_OPTIONS "")
|
||||
if(APPLE)
|
||||
# macOS binaries carry a "debug map" pointing at the .o files rather than embedded DWARF;
|
||||
# atos resolves against the staged .dSYM (see set_target_output_directory) and is fast.
|
||||
list(APPEND CPPTRACE_SYMBOL_OPTIONS
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF OFF"
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE ON"
|
||||
)
|
||||
elseif(UNIX)
|
||||
# Linux: resolve in-process with libdwarf.
|
||||
list(APPEND CPPTRACE_SYMBOL_OPTIONS
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE OFF"
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF ON"
|
||||
"CPPTRACE_USE_EXTERNAL_LIBDWARF ON"
|
||||
"CPPTRACE_FIND_LIBDWARF_WITH_PKGCONFIG ON"
|
||||
)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME cpptrace
|
||||
GITHUB_REPOSITORY jeremy-rifkin/cpptrace
|
||||
GIT_TAG v1.0.4
|
||||
SYSTEM ON
|
||||
OPTIONS
|
||||
${CPPTRACE_SYMBOL_OPTIONS}
|
||||
) # defines: cpptrace::cpptrace
|
||||
|
||||
set(SHARED_EXTERNAL_LIBS
|
||||
fmt::fmt
|
||||
spdlog
|
||||
concurrentqueue
|
||||
spscqueue
|
||||
mariadbclient
|
||||
sol2_single
|
||||
argparse
|
||||
|
|
@ -352,15 +313,25 @@ set(SHARED_EXTERNAL_LIBS
|
|||
magic_enum
|
||||
utf8cpp
|
||||
unordered_dense::unordered_dense
|
||||
function2
|
||||
cpptrace::cpptrace
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
if(WIN32)
|
||||
# add wepoll for epoll support on windows
|
||||
add_subdirectory(wepoll)
|
||||
|
||||
list(APPEND SHARED_EXTERNAL_LIBS
|
||||
wepoll
|
||||
)
|
||||
|
||||
# backwards needs these to add to linker
|
||||
elseif(APPLE)
|
||||
# MacOS has bfd built in clang
|
||||
list(APPEND SHARED_EXTERNAL_LIBS
|
||||
dl
|
||||
)
|
||||
elseif(UNIX)
|
||||
# Linux needs bfd as it's not native like MacOS
|
||||
# bfd may link zstd
|
||||
list(APPEND SHARED_EXTERNAL_LIBS
|
||||
bfd
|
||||
dl
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
add_library(spscqueue INTERFACE)
|
||||
target_sources(spscqueue INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/rigtorp/SPSCQueue.h)
|
||||
target_include_directories(spscqueue SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <memory> // std::allocator
|
||||
#include <new> // std::hardware_destructive_interference_size
|
||||
#include <stdexcept>
|
||||
#include <type_traits> // std::enable_if, std::is_*_constructible
|
||||
|
||||
#ifdef __has_cpp_attribute
|
||||
#if __has_cpp_attribute(nodiscard)
|
||||
#define RIGTORP_NODISCARD [[nodiscard]]
|
||||
#endif
|
||||
#endif
|
||||
#ifndef RIGTORP_NODISCARD
|
||||
#define RIGTORP_NODISCARD
|
||||
#endif
|
||||
|
||||
namespace rigtorp {
|
||||
|
||||
template <typename T, typename Allocator = std::allocator<T>> class SPSCQueue {
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_lib_void_t)
|
||||
template <typename Alloc2, typename = void>
|
||||
struct has_allocate_at_least : std::false_type {};
|
||||
|
||||
template <typename Alloc2>
|
||||
struct has_allocate_at_least<
|
||||
Alloc2, std::void_t<typename Alloc2::value_type,
|
||||
decltype(std::declval<Alloc2 &>().allocate_at_least(
|
||||
size_t{}))>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit SPSCQueue(const size_t capacity,
|
||||
const Allocator &allocator = Allocator())
|
||||
: capacity_(capacity), allocator_(allocator) {
|
||||
// The queue needs at least one element
|
||||
if (capacity_ < 1) {
|
||||
capacity_ = 1;
|
||||
}
|
||||
capacity_++; // Needs one slack element
|
||||
// Prevent overflowing size_t
|
||||
if (capacity_ > SIZE_MAX - 2 * kPadding) {
|
||||
capacity_ = SIZE_MAX - 2 * kPadding;
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_lib_void_t)
|
||||
if constexpr (has_allocate_at_least<Allocator>::value) {
|
||||
auto res = allocator_.allocate_at_least(capacity_ + 2 * kPadding);
|
||||
slots_ = res.ptr;
|
||||
capacity_ = res.count - 2 * kPadding;
|
||||
} else {
|
||||
slots_ = std::allocator_traits<Allocator>::allocate(
|
||||
allocator_, capacity_ + 2 * kPadding);
|
||||
}
|
||||
#else
|
||||
slots_ = std::allocator_traits<Allocator>::allocate(
|
||||
allocator_, capacity_ + 2 * kPadding);
|
||||
#endif
|
||||
|
||||
static_assert(alignof(SPSCQueue<T>) == kCacheLineSize, "");
|
||||
static_assert(sizeof(SPSCQueue<T>) >= 3 * kCacheLineSize, "");
|
||||
assert(reinterpret_cast<char *>(&readIdx_) -
|
||||
reinterpret_cast<char *>(&writeIdx_) >=
|
||||
static_cast<std::ptrdiff_t>(kCacheLineSize));
|
||||
}
|
||||
|
||||
~SPSCQueue() {
|
||||
while (front()) {
|
||||
pop();
|
||||
}
|
||||
std::allocator_traits<Allocator>::deallocate(allocator_, slots_,
|
||||
capacity_ + 2 * kPadding);
|
||||
}
|
||||
|
||||
// non-copyable and non-movable
|
||||
SPSCQueue(const SPSCQueue &) = delete;
|
||||
SPSCQueue &operator=(const SPSCQueue &) = delete;
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args &&...args) noexcept(
|
||||
std::is_nothrow_constructible<T, Args &&...>::value) {
|
||||
static_assert(std::is_constructible<T, Args &&...>::value,
|
||||
"T must be constructible with Args&&...");
|
||||
auto const writeIdx = writeIdx_.load(std::memory_order_relaxed);
|
||||
auto nextWriteIdx = writeIdx + 1;
|
||||
if (nextWriteIdx == capacity_) {
|
||||
nextWriteIdx = 0;
|
||||
}
|
||||
while (nextWriteIdx == readIdxCache_) {
|
||||
readIdxCache_ = readIdx_.load(std::memory_order_acquire);
|
||||
}
|
||||
new (&slots_[writeIdx + kPadding]) T(std::forward<Args>(args)...);
|
||||
writeIdx_.store(nextWriteIdx, std::memory_order_release);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
RIGTORP_NODISCARD bool try_emplace(Args &&...args) noexcept(
|
||||
std::is_nothrow_constructible<T, Args &&...>::value) {
|
||||
static_assert(std::is_constructible<T, Args &&...>::value,
|
||||
"T must be constructible with Args&&...");
|
||||
auto const writeIdx = writeIdx_.load(std::memory_order_relaxed);
|
||||
auto nextWriteIdx = writeIdx + 1;
|
||||
if (nextWriteIdx == capacity_) {
|
||||
nextWriteIdx = 0;
|
||||
}
|
||||
if (nextWriteIdx == readIdxCache_) {
|
||||
readIdxCache_ = readIdx_.load(std::memory_order_acquire);
|
||||
if (nextWriteIdx == readIdxCache_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
new (&slots_[writeIdx + kPadding]) T(std::forward<Args>(args)...);
|
||||
writeIdx_.store(nextWriteIdx, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
void push(const T &v) noexcept(std::is_nothrow_copy_constructible<T>::value) {
|
||||
static_assert(std::is_copy_constructible<T>::value,
|
||||
"T must be copy constructible");
|
||||
emplace(v);
|
||||
}
|
||||
|
||||
template <typename P, typename = typename std::enable_if<
|
||||
std::is_constructible<T, P &&>::value>::type>
|
||||
void push(P &&v) noexcept(std::is_nothrow_constructible<T, P &&>::value) {
|
||||
emplace(std::forward<P>(v));
|
||||
}
|
||||
|
||||
RIGTORP_NODISCARD bool
|
||||
try_push(const T &v) noexcept(std::is_nothrow_copy_constructible<T>::value) {
|
||||
static_assert(std::is_copy_constructible<T>::value,
|
||||
"T must be copy constructible");
|
||||
return try_emplace(v);
|
||||
}
|
||||
|
||||
template <typename P, typename = typename std::enable_if<
|
||||
std::is_constructible<T, P &&>::value>::type>
|
||||
RIGTORP_NODISCARD bool
|
||||
try_push(P &&v) noexcept(std::is_nothrow_constructible<T, P &&>::value) {
|
||||
return try_emplace(std::forward<P>(v));
|
||||
}
|
||||
|
||||
RIGTORP_NODISCARD T *front() noexcept {
|
||||
auto const readIdx = readIdx_.load(std::memory_order_relaxed);
|
||||
if (readIdx == writeIdxCache_) {
|
||||
writeIdxCache_ = writeIdx_.load(std::memory_order_acquire);
|
||||
if (writeIdxCache_ == readIdx) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return &slots_[readIdx + kPadding];
|
||||
}
|
||||
|
||||
void pop() noexcept {
|
||||
static_assert(std::is_nothrow_destructible<T>::value,
|
||||
"T must be nothrow destructible");
|
||||
auto const readIdx = readIdx_.load(std::memory_order_relaxed);
|
||||
assert(writeIdx_.load(std::memory_order_acquire) != readIdx &&
|
||||
"Can only call pop() after front() has returned a non-nullptr");
|
||||
slots_[readIdx + kPadding].~T();
|
||||
auto nextReadIdx = readIdx + 1;
|
||||
if (nextReadIdx == capacity_) {
|
||||
nextReadIdx = 0;
|
||||
}
|
||||
readIdx_.store(nextReadIdx, std::memory_order_release);
|
||||
}
|
||||
|
||||
RIGTORP_NODISCARD size_t size() const noexcept {
|
||||
std::ptrdiff_t diff = writeIdx_.load(std::memory_order_acquire) -
|
||||
readIdx_.load(std::memory_order_acquire);
|
||||
if (diff < 0) {
|
||||
diff += capacity_;
|
||||
}
|
||||
return static_cast<size_t>(diff);
|
||||
}
|
||||
|
||||
RIGTORP_NODISCARD bool empty() const noexcept {
|
||||
return writeIdx_.load(std::memory_order_acquire) ==
|
||||
readIdx_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
RIGTORP_NODISCARD size_t capacity() const noexcept { return capacity_ - 1; }
|
||||
|
||||
private:
|
||||
#ifdef __cpp_lib_hardware_interference_size
|
||||
static constexpr size_t kCacheLineSize =
|
||||
std::hardware_destructive_interference_size;
|
||||
#else
|
||||
static constexpr size_t kCacheLineSize = 64;
|
||||
#endif
|
||||
|
||||
// Padding to avoid false sharing between slots_ and adjacent allocations
|
||||
static constexpr size_t kPadding = (kCacheLineSize - 1) / sizeof(T) + 1;
|
||||
|
||||
private:
|
||||
size_t capacity_;
|
||||
T *slots_;
|
||||
#if defined(__has_cpp_attribute) && __has_cpp_attribute(no_unique_address)
|
||||
Allocator allocator_ [[no_unique_address]];
|
||||
#else
|
||||
Allocator allocator_;
|
||||
#endif
|
||||
|
||||
// Align to cache line size in order to avoid false sharing
|
||||
// readIdxCache_ and writeIdxCache_ is used to reduce the amount of cache
|
||||
// coherency traffic
|
||||
alignas(kCacheLineSize) std::atomic<size_t> writeIdx_ = {0};
|
||||
alignas(kCacheLineSize) size_t readIdxCache_ = 0;
|
||||
alignas(kCacheLineSize) std::atomic<size_t> readIdx_ = {0};
|
||||
alignas(kCacheLineSize) size_t writeIdxCache_ = 0;
|
||||
};
|
||||
} // namespace rigtorp
|
||||
21
ext/backward/LICENSE.txt
Normal file
21
ext/backward/LICENSE.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
42
ext/backward/backward.cpp
Normal file
42
ext/backward/backward.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Pick your poison.
|
||||
//
|
||||
// On GNU/Linux, you have few choices to get the most out of your stack trace.
|
||||
//
|
||||
// By default you get:
|
||||
// - object filename
|
||||
// - function name
|
||||
//
|
||||
// In order to add:
|
||||
// - source filename
|
||||
// - line and column numbers
|
||||
// - source code snippet (assuming the file is accessible)
|
||||
|
||||
// Install one of the following libraries then uncomment one of the macro (or
|
||||
// better, add the detection of the lib and the macro definition in your build
|
||||
// system)
|
||||
|
||||
// - apt-get install libdw-dev ...
|
||||
// - g++/clang++ -ldw ...
|
||||
// #define BACKWARD_HAS_DW 1
|
||||
|
||||
// - apt-get install binutils-dev ...
|
||||
// - g++/clang++ -lbfd ...
|
||||
// #define BACKWARD_HAS_BFD 1
|
||||
|
||||
// - apt-get install libdwarf-dev ...
|
||||
// - g++/clang++ -ldwarf ...
|
||||
// #define BACKWARD_HAS_DWARF 1
|
||||
|
||||
// Regardless of the library you choose to read the debug information,
|
||||
// for potentially more detailed stack traces you can use libunwind
|
||||
// - apt-get install libunwind-dev
|
||||
// - g++/clang++ -lunwind
|
||||
// #define BACKWARD_HAS_LIBUNWIND 1
|
||||
|
||||
#include "backward.hpp"
|
||||
|
||||
namespace backward {
|
||||
|
||||
backward::SignalHandling sh;
|
||||
|
||||
} // namespace backward
|
||||
4514
ext/backward/backward.hpp
Normal file
4514
ext/backward/backward.hpp
Normal file
File diff suppressed because it is too large
Load diff
9
ext/wepoll/CMakeLists.txt
Normal file
9
ext/wepoll/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
set(SOURCES
|
||||
wepoll.c
|
||||
wepoll.h
|
||||
)
|
||||
|
||||
add_library(wepoll STATIC ${SOURCES})
|
||||
target_include_directories(wepoll SYSTEM PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
28
ext/wepoll/LICENSE
Normal file
28
ext/wepoll/LICENSE
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
wepoll - epoll for Windows
|
||||
https://github.com/piscisaureus/wepoll
|
||||
|
||||
Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
202
ext/wepoll/README.md
Normal file
202
ext/wepoll/README.md
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
# wepoll - epoll for windows
|
||||
|
||||
[![][ci status badge]][ci status link]
|
||||
|
||||
This library implements the [epoll][man epoll] API for Windows
|
||||
applications. It is fast and scalable, and it closely resembles the API
|
||||
and behavior of Linux' epoll.
|
||||
|
||||
## Rationale
|
||||
|
||||
Unlike Linux, OS X, and many other operating systems, Windows doesn't
|
||||
have a good API for receiving socket state notifications. It only
|
||||
supports the `select` and `WSAPoll` APIs, but they
|
||||
[don't scale][select scale] and suffer from
|
||||
[other issues][wsapoll broken].
|
||||
|
||||
Using I/O completion ports isn't always practical when software is
|
||||
designed to be cross-platform. Wepoll offers an alternative that is
|
||||
much closer to a drop-in replacement for software that was designed
|
||||
to run on Linux.
|
||||
|
||||
## Features
|
||||
|
||||
* Can poll 100000s of sockets efficiently.
|
||||
* Fully thread-safe.
|
||||
* Multiple threads can poll the same epoll port.
|
||||
* Sockets can be added to multiple epoll sets.
|
||||
* All epoll events (`EPOLLIN`, `EPOLLOUT`, `EPOLLPRI`, `EPOLLRDHUP`)
|
||||
are supported.
|
||||
* Level-triggered and one-shot (`EPOLLONESTHOT`) modes are supported
|
||||
* Trivial to embed: you need [only two files][dist].
|
||||
|
||||
## Limitations
|
||||
|
||||
* Only works with sockets.
|
||||
* Edge-triggered (`EPOLLET`) mode isn't supported.
|
||||
|
||||
## How to use
|
||||
|
||||
The library is [distributed][dist] as a single source file
|
||||
([wepoll.c][wepoll.c]) and a single header file ([wepoll.h][wepoll.h]).<br>
|
||||
Compile the .c file as part of your project, and include the header wherever
|
||||
needed.
|
||||
|
||||
## Compatibility
|
||||
|
||||
* Requires Windows Vista or higher.
|
||||
* Can be compiled with recent versions of MSVC, Clang, and GCC.
|
||||
|
||||
## API
|
||||
|
||||
### General remarks
|
||||
|
||||
* The epoll port is a `HANDLE`, not a file descriptor.
|
||||
* All functions set both `errno` and `GetLastError()` on failure.
|
||||
* For more extensive documentation, see the [epoll(7) man page][man epoll],
|
||||
and the per-function man pages that are linked below.
|
||||
|
||||
### epoll_create/epoll_create1
|
||||
|
||||
```c
|
||||
HANDLE epoll_create(int size);
|
||||
HANDLE epoll_create1(int flags);
|
||||
```
|
||||
|
||||
* Create a new epoll instance (port).
|
||||
* `size` is ignored but most be greater than zero.
|
||||
* `flags` must be zero as there are no supported flags.
|
||||
* Returns `NULL` on failure.
|
||||
* [Linux man page][man epoll_create]
|
||||
|
||||
### epoll_close
|
||||
|
||||
```c
|
||||
int epoll_close(HANDLE ephnd);
|
||||
```
|
||||
|
||||
* Close an epoll port.
|
||||
* Do not attempt to close the epoll port with `close()`,
|
||||
`CloseHandle()` or `closesocket()`.
|
||||
|
||||
### epoll_ctl
|
||||
|
||||
```c
|
||||
int epoll_ctl(HANDLE ephnd,
|
||||
int op,
|
||||
SOCKET sock,
|
||||
struct epoll_event* event);
|
||||
```
|
||||
|
||||
* Control which socket events are monitored by an epoll port.
|
||||
* `ephnd` must be a HANDLE created by
|
||||
[`epoll_create()`](#epoll_createepoll_create1) or
|
||||
[`epoll_create1()`](#epoll_createepoll_create1).
|
||||
* `op` must be one of `EPOLL_CTL_ADD`, `EPOLL_CTL_MOD`, `EPOLL_CTL_DEL`.
|
||||
* `sock` must be a valid socket created by [`socket()`][msdn socket],
|
||||
[`WSASocket()`][msdn wsasocket], or [`accept()`][msdn accept].
|
||||
* `event` should be a pointer to a [`struct epoll_event`](#struct-epoll_event).<br>
|
||||
If `op` is `EPOLL_CTL_DEL` then the `event` parameter is ignored, and it
|
||||
may be `NULL`.
|
||||
* Returns 0 on success, -1 on failure.
|
||||
* It is recommended to always explicitly remove a socket from its epoll
|
||||
set using `EPOLL_CTL_DEL` *before* closing it.<br>
|
||||
As on Linux, closed sockets are automatically removed from the epoll set, but
|
||||
wepoll may not be able to detect that a socket was closed until the next call
|
||||
to [`epoll_wait()`](#epoll_wait).
|
||||
* [Linux man page][man epoll_ctl]
|
||||
|
||||
### epoll_wait
|
||||
|
||||
```c
|
||||
int epoll_wait(HANDLE ephnd,
|
||||
struct epoll_event* events,
|
||||
int maxevents,
|
||||
int timeout);
|
||||
```
|
||||
|
||||
* Receive socket events from an epoll port.
|
||||
* `events` should point to a caller-allocated array of
|
||||
[`epoll_event`](#struct-epoll_event) structs, which will receive the
|
||||
reported events.
|
||||
* `maxevents` is the maximum number of events that will be written to the
|
||||
`events` array, and must be greater than zero.
|
||||
* `timeout` specifies whether to block when no events are immediately available.
|
||||
- `<0` block indefinitely
|
||||
- `0` report any events that are already waiting, but don't block
|
||||
- `≥1` block for at most N milliseconds
|
||||
* Return value:
|
||||
- `-1` an error occurred
|
||||
- `0` timed out without any events to report
|
||||
- `≥1` the number of events stored in the `events` buffer
|
||||
* [Linux man page][man epoll_wait]
|
||||
|
||||
### struct epoll_event
|
||||
|
||||
```c
|
||||
typedef union epoll_data {
|
||||
void* ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
SOCKET sock; /* Windows specific */
|
||||
HANDLE hnd; /* Windows specific */
|
||||
} epoll_data_t;
|
||||
```
|
||||
|
||||
```c
|
||||
struct epoll_event {
|
||||
uint32_t events; /* Epoll events and flags */
|
||||
epoll_data_t data; /* User data variable */
|
||||
};
|
||||
```
|
||||
|
||||
* The `events` field is a bit mask containing the events being
|
||||
monitored/reported, and optional flags.<br>
|
||||
Flags are accepted by [`epoll_ctl()`](#epoll_ctl), but they are not reported
|
||||
back by [`epoll_wait()`](#epoll_wait).
|
||||
* The `data` field can be used to associate application-specific information
|
||||
with a socket; its value will be returned unmodified by
|
||||
[`epoll_wait()`](#epoll_wait).
|
||||
* [Linux man page][man epoll_ctl]
|
||||
|
||||
| Event | Description |
|
||||
|---------------|----------------------------------------------------------------------|
|
||||
| `EPOLLIN` | incoming data available, or incoming connection ready to be accepted |
|
||||
| `EPOLLOUT` | ready to send data, or outgoing connection successfully established |
|
||||
| `EPOLLRDHUP` | remote peer initiated graceful socket shutdown |
|
||||
| `EPOLLPRI` | out-of-band data available for reading |
|
||||
| `EPOLLERR` | socket error<sup>1</sup> |
|
||||
| `EPOLLHUP` | socket hang-up<sup>1</sup> |
|
||||
| `EPOLLRDNORM` | same as `EPOLLIN` |
|
||||
| `EPOLLRDBAND` | same as `EPOLLPRI` |
|
||||
| `EPOLLWRNORM` | same as `EPOLLOUT` |
|
||||
| `EPOLLWRBAND` | same as `EPOLLOUT` |
|
||||
| `EPOLLMSG` | never reported |
|
||||
|
||||
| Flag | Description |
|
||||
|------------------|---------------------------|
|
||||
| `EPOLLONESHOT` | report event(s) only once |
|
||||
| `EPOLLET` | not supported by wepoll |
|
||||
| `EPOLLEXCLUSIVE` | not supported by wepoll |
|
||||
| `EPOLLWAKEUP` | not supported by wepoll |
|
||||
|
||||
<sup>1</sup>: the `EPOLLERR` and `EPOLLHUP` events may always be reported by
|
||||
[`epoll_wait()`](#epoll_wait), regardless of the event mask that was passed to
|
||||
[`epoll_ctl()`](#epoll_ctl).
|
||||
|
||||
|
||||
[ci status badge]: https://ci.appveyor.com/api/projects/status/github/piscisaureus/wepoll?branch=master&svg=true
|
||||
[ci status link]: https://ci.appveyor.com/project/piscisaureus/wepoll/branch/master
|
||||
[dist]: https://github.com/piscisaureus/wepoll/tree/dist
|
||||
[man epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
|
||||
[man epoll_create]: http://man7.org/linux/man-pages/man2/epoll_create.2.html
|
||||
[man epoll_ctl]: http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
|
||||
[man epoll_wait]: http://man7.org/linux/man-pages/man2/epoll_wait.2.html
|
||||
[msdn accept]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx
|
||||
[msdn socket]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
|
||||
[msdn wsasocket]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
|
||||
[select scale]: https://daniel.haxx.se/docs/poll-vs-select.html
|
||||
[wsapoll broken]: https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
|
||||
[wepoll.c]: https://github.com/piscisaureus/wepoll/blob/dist/wepoll.c
|
||||
[wepoll.h]: https://github.com/piscisaureus/wepoll/blob/dist/wepoll.h
|
||||
2253
ext/wepoll/wepoll.c
Normal file
2253
ext/wepoll/wepoll.c
Normal file
File diff suppressed because it is too large
Load diff
113
ext/wepoll/wepoll.h
Normal file
113
ext/wepoll/wepoll.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* wepoll - epoll for Windows
|
||||
* https://github.com/piscisaureus/wepoll
|
||||
*
|
||||
* Copyright 2012-2020, Bert Belder <bertbelder@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WEPOLL_H_
|
||||
#define WEPOLL_H_
|
||||
|
||||
#ifndef WEPOLL_EXPORT
|
||||
#define WEPOLL_EXPORT
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum EPOLL_EVENTS {
|
||||
EPOLLIN = (int) (1U << 0),
|
||||
EPOLLPRI = (int) (1U << 1),
|
||||
EPOLLOUT = (int) (1U << 2),
|
||||
EPOLLERR = (int) (1U << 3),
|
||||
EPOLLHUP = (int) (1U << 4),
|
||||
EPOLLRDNORM = (int) (1U << 6),
|
||||
EPOLLRDBAND = (int) (1U << 7),
|
||||
EPOLLWRNORM = (int) (1U << 8),
|
||||
EPOLLWRBAND = (int) (1U << 9),
|
||||
EPOLLMSG = (int) (1U << 10), /* Never reported. */
|
||||
EPOLLRDHUP = (int) (1U << 13),
|
||||
EPOLLONESHOT = (int) (1U << 31)
|
||||
};
|
||||
|
||||
#define EPOLLIN (1U << 0)
|
||||
#define EPOLLPRI (1U << 1)
|
||||
#define EPOLLOUT (1U << 2)
|
||||
#define EPOLLERR (1U << 3)
|
||||
#define EPOLLHUP (1U << 4)
|
||||
#define EPOLLRDNORM (1U << 6)
|
||||
#define EPOLLRDBAND (1U << 7)
|
||||
#define EPOLLWRNORM (1U << 8)
|
||||
#define EPOLLWRBAND (1U << 9)
|
||||
#define EPOLLMSG (1U << 10)
|
||||
#define EPOLLRDHUP (1U << 13)
|
||||
#define EPOLLONESHOT (1U << 31)
|
||||
|
||||
#define EPOLL_CTL_ADD 1
|
||||
#define EPOLL_CTL_MOD 2
|
||||
#define EPOLL_CTL_DEL 3
|
||||
|
||||
typedef void* HANDLE;
|
||||
typedef uintptr_t SOCKET;
|
||||
|
||||
typedef union epoll_data {
|
||||
void* ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
SOCKET sock; /* Windows specific */
|
||||
HANDLE hnd; /* Windows specific */
|
||||
} epoll_data_t;
|
||||
|
||||
struct epoll_event {
|
||||
uint32_t events; /* Epoll events and flags */
|
||||
epoll_data_t data; /* User data variable */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WEPOLL_EXPORT HANDLE epoll_create(int size);
|
||||
WEPOLL_EXPORT HANDLE epoll_create1(int flags);
|
||||
|
||||
WEPOLL_EXPORT int epoll_close(HANDLE ephnd);
|
||||
|
||||
WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,
|
||||
int op,
|
||||
SOCKET sock,
|
||||
struct epoll_event* event);
|
||||
|
||||
WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
|
||||
struct epoll_event* events,
|
||||
int maxevents,
|
||||
int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WEPOLL_H_ */
|
||||
|
|
@ -89,7 +89,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.Zone.onInitialize', function(zone)
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Fafnir', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -99,7 +99,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.Zone.onInitialize', function(zone)
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = dragonsAeryID.mob.NIDHOGG
|
||||
end
|
||||
|
|
@ -122,7 +122,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.mobs.Fafnir.onMobDespawn', function
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
local hnmKillCount = GetServerVariable('[HNM]Fafnir_C') + 1
|
||||
|
||||
SetServerVariable('[HNM]Fafnir', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
|
@ -133,7 +133,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.mobs.Fafnir.onMobDespawn', function
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = dragonsAeryID.mob.NIDHOGG
|
||||
end
|
||||
|
|
@ -146,7 +146,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.mobs.Nidhogg.onMobDespawn', functio
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Fafnir', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
SetServerVariable('[HNM]Fafnir_C', 0) -- Save kill count.
|
||||
|
|
@ -222,7 +222,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.Zone.onInitialize', function(z
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Adamantoise', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -232,7 +232,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.Zone.onInitialize', function(z
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = valleySorrowsID.mob.ASPIDOCHELONE
|
||||
end
|
||||
|
|
@ -255,7 +255,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.mobs.Adamantoise.onMobDespawn'
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
local hnmKillCount = GetServerVariable('[HNM]Adamantoise_C') + 1
|
||||
|
||||
SetServerVariable('[HNM]Adamantoise', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
|
@ -266,7 +266,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.mobs.Adamantoise.onMobDespawn'
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = valleySorrowsID.mob.ASPIDOCHELONE
|
||||
end
|
||||
|
|
@ -279,7 +279,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.mobs.Aspidochelone.onMobDespaw
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Adamantoise', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
SetServerVariable('[HNM]Adamantoise_C', 0) -- Save kill count.
|
||||
|
|
@ -355,7 +355,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.Zone.onInitialize', function(
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Behemoth', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -365,7 +365,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.Zone.onInitialize', function(
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = behemothDomID.mob.KING_BEHEMOTH
|
||||
end
|
||||
|
|
@ -388,7 +388,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.mobs.Behemoth.onMobDespawn',
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
local hnmKillCount = GetServerVariable('[HNM]Behemoth_C') + 1
|
||||
|
||||
SetServerVariable('[HNM]Behemoth', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
|
@ -399,7 +399,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.mobs.Behemoth.onMobDespawn',
|
|||
|
||||
if
|
||||
hnmKillCount > 3 and
|
||||
(math.randomInt(1, 5) == 3 or hnmKillCount > 6)
|
||||
(math.random(1, 5) == 3 or hnmKillCount > 6)
|
||||
then
|
||||
monster = behemothDomID.mob.KING_BEHEMOTH
|
||||
end
|
||||
|
|
@ -412,7 +412,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.mobs.King_Behemoth.onMobDespa
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Behemoth', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
SetServerVariable('[HNM]Behemoth_C', 0) -- Save kill count.
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
-----------------------------------
|
||||
-- NIN/DRG/SAM Quest Mobs Original Difficulty Module
|
||||
-- Reverts the nerfs to the NIN/DRG/SAM quest mobs in the May 10, 2011 version update
|
||||
-- Source: https://forum.square-enix.com/ffxi/threads/7257
|
||||
-----------------------------------
|
||||
|
||||
-- Level: set all six spawns to level 32 (min == max => fixed level)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17486187; -- Korroloka Leech (Korroloka Tunnel)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17486188; -- Korroloka Leech (Korroloka Tunnel)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17486189; -- Korroloka Leech (Korroloka Tunnel)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17350928; -- Cyranuce M Cutauleon (Ghelsba Outpost)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17219999; -- Forger (Konschtat Highlands)
|
||||
UPDATE mob_spawn_points SET minLevel = 32, maxLevel = 32 WHERE mobid = 17272838; -- Guardian Treant (The Sanctuary of Zi'Tah)
|
||||
|
||||
-- HP: per-group override, keyed by (groupid, zoneid)
|
||||
UPDATE mob_groups SET HP = 900 WHERE groupid = 28 AND zoneid = 173; -- Korroloka Leech x3 (Korroloka Tunnel)
|
||||
UPDATE mob_groups SET HP = 2700 WHERE groupid = 26 AND zoneid = 140; -- Cyranuce M Cutauleon (Ghelsba Outpost)
|
||||
UPDATE mob_groups SET HP = 2000 WHERE groupid = 33 AND zoneid = 108; -- Forger (Konschtat Highlands)
|
||||
UPDATE mob_groups SET HP = 2000 WHERE groupid = 5 AND zoneid = 121; -- Guardian Treant (The Sanctuary of Zi'Tah)
|
||||
|
|
@ -69,8 +69,7 @@ UPDATE merits SET value = 20 WHERE name = 'arcane_circle_recast';
|
|||
UPDATE abilities SET recastTime = 300 WHERE name = 'weapon_bash';
|
||||
|
||||
-- Weapon Bash merit: Revert value to 10 seconds per level
|
||||
-- Note: merit is named weapon_bash_effect (provides both recast reduction and effect)
|
||||
UPDATE merits SET value = 10 WHERE name = 'weapon_bash_effect';
|
||||
UPDATE merits SET value = 10 WHERE name = 'weapon_bash_recast';
|
||||
|
||||
-- Dark Seal: Revert recast from 5 to 15 minutes
|
||||
-- Source: https://www.bg-wiki.com/ffxi/Version_Update_(03/26/2012)
|
||||
|
|
@ -252,14 +251,6 @@ UPDATE abilities SET recastTime = 900 WHERE name = 'deep_breathing';
|
|||
-- Deep Breathing merit: Revert value to 150 seconds per level
|
||||
UPDATE merits SET value = 150 WHERE name = 'deep_breathing';
|
||||
|
||||
-----------------------------------
|
||||
-- Summoner
|
||||
-----------------------------------
|
||||
|
||||
-- Summoning Magic Casting Time Merit: Repurposed to Spirit MP cost merit. Revert merit value from 5 to 1 per level.
|
||||
-- Source: https://forum.square-enix.com/ffxi/threads/22099-March-27-2012-%28JST%29-Version-Update
|
||||
UPDATE merits SET value = 1 WHERE name = 'summoning_magic_cast_time';
|
||||
|
||||
-----------------------------------
|
||||
-- Corsair
|
||||
-----------------------------------
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class AHPaginationModule : public CPPModule
|
|||
return false;
|
||||
}
|
||||
|
||||
if (PChar->m_GMlevel == 0 && !PChar->loc.zone->CanUseMisc(xi::ZoneMisc::AuctionHouse))
|
||||
if (PChar->m_GMlevel == 0 && !PChar->loc.zone->CanUseMisc(MISC_AH))
|
||||
{
|
||||
ShowWarning("[AH PAGES] %s is trying to use the auction house in a disallowed zone [%s]", PChar->getName(), PChar->loc.zone->getName());
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.Zone.onInitialize', function(zone)
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Fafnir', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -54,7 +54,7 @@ hnmSystem:addOverride('xi.zones.Dragons_Aery.mobs.Fafnir.onMobDespawn', function
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Fafnir', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.Zone.onInitialize', function(z
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Adamantoise', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -104,7 +104,7 @@ hnmSystem:addOverride('xi.zones.Valley_of_Sorrows.mobs.Adamantoise.onMobDespawn'
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Adamantoise', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.Zone.onInitialize', function(
|
|||
|
||||
-- First-time setup.
|
||||
if hnmPopTime == 0 then
|
||||
hnmPopTime = currentTime + math.randomInt(1, 48) * 1800
|
||||
hnmPopTime = currentTime + math.random(1, 48) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Behemoth', hnmPopTime) -- Save pop time.
|
||||
end
|
||||
|
|
@ -154,7 +154,7 @@ hnmSystem:addOverride('xi.zones.Behemoths_Dominion.mobs.Behemoth.onMobDespawn',
|
|||
super(mob)
|
||||
|
||||
-- Server Variable work.
|
||||
local randomPopTime = 75600 + math.randomInt(0, 6) * 1800
|
||||
local randomPopTime = 75600 + math.random(0, 6) * 1800
|
||||
|
||||
SetServerVariable('[HNM]Behemoth', GetSystemTime() + randomPopTime) -- Save next pop time.
|
||||
|
||||
|
|
|
|||
20
modules/custom/lua/missable_mom_the_adventurer.lua
Normal file
20
modules/custom/lua/missable_mom_the_adventurer.lua
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
-----------------------------------
|
||||
-- Module to make 'Mom the Adventurer?' quest missable.
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local m = Module:new('missable_mom_the_adventurer')
|
||||
|
||||
m:addOverride('xi.server.onServerStart', function()
|
||||
super()
|
||||
|
||||
xi.module.modifyInteractionEntry('scripts/quests/bastok/Mom_the_Adventurer', function(quest)
|
||||
quest.sections[1].check = function(player, status, vars)
|
||||
return status ~= xi.questStatus.QUEST_ACCEPTED and
|
||||
player:getFameLevel(xi.fameArea.BASTOK) < 2 and
|
||||
vars.Prog == 0
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Mog House Exit Home Point Prompt Module
|
||||
-----------------------------------
|
||||
-- Restores the prompt to set your home point when exiting the Mog House after changing jobs.
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
require('scripts/globals/moghouse')
|
||||
-----------------------------------
|
||||
local m = Module:new('moghouse_exit_homepoint')
|
||||
|
||||
-- Variable used for this module to store the job snapshot in the player's character variables.
|
||||
local jobSnapshot = 'moghouseExitJobSnapshot'
|
||||
|
||||
-- The current event ID for the Mog House exit prompt. May change with future updates. If this module ever breaks, check here first.
|
||||
local exitEventId = 30004
|
||||
|
||||
-- Zones to prompt players to set their home point upon exiting the Mog House.
|
||||
local exitZones =
|
||||
{
|
||||
['Southern_San_dOria' ] = xi.zone.SOUTHERN_SAN_DORIA,
|
||||
['Northern_San_dOria' ] = xi.zone.NORTHERN_SAN_DORIA,
|
||||
['Port_San_dOria' ] = xi.zone.PORT_SAN_DORIA,
|
||||
['Bastok_Mines' ] = xi.zone.BASTOK_MINES,
|
||||
['Bastok_Markets' ] = xi.zone.BASTOK_MARKETS,
|
||||
['Port_Bastok' ] = xi.zone.PORT_BASTOK,
|
||||
['Windurst_Waters' ] = xi.zone.WINDURST_WATERS,
|
||||
['Windurst_Walls' ] = xi.zone.WINDURST_WALLS,
|
||||
['Port_Windurst' ] = xi.zone.PORT_WINDURST,
|
||||
['Windurst_Woods' ] = xi.zone.WINDURST_WOODS,
|
||||
['RuLude_Gardens' ] = xi.zone.RULUDE_GARDENS,
|
||||
['Upper_Jeuno' ] = xi.zone.UPPER_JEUNO,
|
||||
['Lower_Jeuno' ] = xi.zone.LOWER_JEUNO,
|
||||
['Port_Jeuno' ] = xi.zone.PORT_JEUNO,
|
||||
['Al_Zahbi' ] = xi.zone.AL_ZAHBI,
|
||||
['Aht_Urhgan_Whitegate' ] = xi.zone.AHT_URHGAN_WHITEGATE,
|
||||
['Southern_San_dOria_[S]'] = xi.zone.SOUTHERN_SAN_DORIA_S,
|
||||
['Bastok_Markets_[S]' ] = xi.zone.BASTOK_MARKETS_S,
|
||||
['Windurst_Waters_[S]' ] = xi.zone.WINDURST_WATERS_S,
|
||||
}
|
||||
|
||||
local promptZoneIds = {}
|
||||
for _, zoneId in pairs(exitZones) do
|
||||
promptZoneIds[zoneId] = true
|
||||
end
|
||||
|
||||
local currentJob = function(player)
|
||||
return player:getMainJob() * 100 + player:getSubJob()
|
||||
end
|
||||
|
||||
m:addOverride('xi.moghouse.onMoghouseZoneEvent', function(player, prevZone)
|
||||
-- Create a snapshot of the players current job when entering the mog house.
|
||||
if player:inMogHouse() then
|
||||
player:setCharVar(jobSnapshot, currentJob(player))
|
||||
|
||||
return super(player, prevZone)
|
||||
end
|
||||
|
||||
local moghouseExitPos = player:getXPos() == 0 and player:getYPos() == 0 and player:getZPos() == 0
|
||||
local baseCsId = super(player, prevZone)
|
||||
local storedJob = player:getCharVar(jobSnapshot)
|
||||
|
||||
if moghouseExitPos and storedJob > 0 then
|
||||
player:setCharVar(jobSnapshot, 0)
|
||||
|
||||
if
|
||||
baseCsId == -1 and
|
||||
promptZoneIds[player:getZoneID()] and
|
||||
storedJob ~= currentJob(player)
|
||||
then
|
||||
return exitEventId
|
||||
end
|
||||
end
|
||||
|
||||
return baseCsId
|
||||
end)
|
||||
|
||||
for zoneName in pairs(exitZones) do
|
||||
m:addOverride(string.format('xi.zones.%s.Zone.onEventFinish', zoneName), function(player, csid, option, npc)
|
||||
if csid == exitEventId then
|
||||
if option == 0 then
|
||||
player:setHomePoint()
|
||||
player:messageSpecial(zones[player:getZoneID()].text.HOMEPOINT_SET)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
super(player, csid, option, npc)
|
||||
end)
|
||||
end
|
||||
|
||||
return m
|
||||
|
|
@ -20,7 +20,7 @@ local nmsToPersist =
|
|||
'Behemoths_Dominion',
|
||||
'Behemoth',
|
||||
function()
|
||||
return 75600 + math.randomInt(0, 6) * 1800
|
||||
return 75600 + math.random(0, 6) * 1800
|
||||
end
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,297 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Reverts blood pacts to no longer have a duration based on summoning magic.
|
||||
-- Source: https://www.bg-wiki.com/ffxi/Version_Update_(09/08/2010)
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'abyssea_avatar_bloodpacts'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
-----------------------------------
|
||||
-- Shining Ruby
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.shining_ruby.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
target:delStatusEffect(xi.effect.SHINING_RUBY)
|
||||
target:addStatusEffect(xi.effect.SHINING_RUBY, { power = 1, duration = duration, origin = pet })
|
||||
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
|
||||
return xi.effect.SHINING_RUBY
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Hastega
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.hastega.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
-- Reverts Garuda's Hastega to use 102/1024 or 9.96%
|
||||
local typeEffect = xi.effect.HASTE
|
||||
if target:addStatusEffect(typeEffect, { power = 996, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return typeEffect
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Crimson Howl
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.crimson_howl.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 60
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local typeEffect = xi.effect.WARCRY
|
||||
if target:addStatusEffect(typeEffect, { power = 9, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return typeEffect
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Frost Armor
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.frost_armor.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local typeEffect = xi.effect.ICE_SPIKES
|
||||
target:delStatusEffect(typeEffect)
|
||||
|
||||
if target:addStatusEffect(typeEffect, { power = 15, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return typeEffect
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Rolling Thunder
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.rolling_thunder.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 120
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local magicskill = xi.data.skillLevel.getSkillCap(target:getMainLvl(), xi.skillRank.A_PLUS)
|
||||
local potency = 3 + 6 * magicskill / 100
|
||||
|
||||
if magicskill > 200 then
|
||||
potency = 5 + 5 * magicskill / 100
|
||||
end
|
||||
|
||||
xi.mobskills.mobBuffMove(target, xi.effect.ENTHUNDER, potency, 0, duration)
|
||||
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.JA_RECEIVES_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_RECEIVES_EFFECT)
|
||||
end
|
||||
|
||||
return xi.effect.ENTHUNDER
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Lightning Armor
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.lightning_armor.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local typeEffect = xi.effect.SHOCK_SPIKES
|
||||
target:delStatusEffect(typeEffect)
|
||||
|
||||
if target:addStatusEffect(typeEffect, { power = 15, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return typeEffect
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Ecliptic Growl
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.ecliptic_growl.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local moonCycle = getVanadielMoonCycle()
|
||||
|
||||
local cycleBuffs =
|
||||
{
|
||||
[xi.moonCycle.NEW_MOON] = 1,
|
||||
[xi.moonCycle.LESSER_WAXING_CRESCENT] = 2,
|
||||
[xi.moonCycle.GREATER_WAXING_CRESCENT] = 3,
|
||||
[xi.moonCycle.FIRST_QUARTER] = 4,
|
||||
[xi.moonCycle.LESSER_WAXING_GIBBOUS] = 5,
|
||||
[xi.moonCycle.GREATER_WAXING_GIBBOUS] = 6,
|
||||
[xi.moonCycle.FULL_MOON] = 7,
|
||||
[xi.moonCycle.GREATER_WANING_GIBBOUS] = 6,
|
||||
[xi.moonCycle.LESSER_WANING_GIBBOUS] = 5,
|
||||
[xi.moonCycle.THIRD_QUARTER] = 4,
|
||||
[xi.moonCycle.GREATER_WANING_CRESCENT] = 3,
|
||||
[xi.moonCycle.LESSER_WANING_CRESCENT] = 2,
|
||||
}
|
||||
|
||||
local buffValue = cycleBuffs[moonCycle]
|
||||
|
||||
target:delStatusEffect(xi.effect.STR_BOOST)
|
||||
target:delStatusEffect(xi.effect.DEX_BOOST)
|
||||
target:delStatusEffect(xi.effect.VIT_BOOST)
|
||||
target:delStatusEffect(xi.effect.AGI_BOOST)
|
||||
target:delStatusEffect(xi.effect.MND_BOOST)
|
||||
target:delStatusEffect(xi.effect.CHR_BOOST)
|
||||
|
||||
target:addStatusEffect(xi.effect.STR_BOOST, { power = buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.DEX_BOOST, { power = buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.VIT_BOOST, { power = buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.AGI_BOOST, { power = 8 - buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.INT_BOOST, { power = 8 - buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.MND_BOOST, { power = 8 - buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.CHR_BOOST, { power = 8 - buffValue, duration = duration, origin = pet })
|
||||
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.STATUS_BOOST)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.STATUS_BOOST_2)
|
||||
end
|
||||
|
||||
return 0
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Ecliptic Howl
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.ecliptic_howl.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
local moonCycle = getVanadielMoonCycle()
|
||||
|
||||
local cycleBuffs =
|
||||
{
|
||||
[xi.moonCycle.NEW_MOON] = 1,
|
||||
[xi.moonCycle.LESSER_WAXING_CRESCENT] = 5,
|
||||
[xi.moonCycle.GREATER_WAXING_CRESCENT] = 9,
|
||||
[xi.moonCycle.FIRST_QUARTER] = 13,
|
||||
[xi.moonCycle.LESSER_WAXING_GIBBOUS] = 17,
|
||||
[xi.moonCycle.GREATER_WAXING_GIBBOUS] = 21,
|
||||
[xi.moonCycle.FULL_MOON] = 25,
|
||||
[xi.moonCycle.GREATER_WANING_GIBBOUS] = 21,
|
||||
[xi.moonCycle.LESSER_WANING_GIBBOUS] = 17,
|
||||
[xi.moonCycle.THIRD_QUARTER] = 13,
|
||||
[xi.moonCycle.GREATER_WANING_CRESCENT] = 9,
|
||||
[xi.moonCycle.LESSER_WANING_CRESCENT] = 5,
|
||||
}
|
||||
|
||||
local buffValue = cycleBuffs[moonCycle]
|
||||
|
||||
target:delStatusEffect(xi.effect.ACCURACY_BOOST)
|
||||
target:delStatusEffect(xi.effect.EVASION_BOOST)
|
||||
target:addStatusEffect(xi.effect.ACCURACY_BOOST, { power = buffValue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.EVASION_BOOST, { power = 25 - buffValue, duration = duration, origin = pet })
|
||||
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.ACC_EVA_BOOST)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.ACC_EVA_BOOST_2)
|
||||
end
|
||||
|
||||
return 0
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Noctoshield
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.noctoshield.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
if target:addStatusEffect(xi.effect.PHALANX, { power = 13, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return xi.effect.PHALANX
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Dream Shroud
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.dream_shroud.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
local duration = 180
|
||||
local hour = VanadielHour()
|
||||
local buffvalue = math.abs(12 - hour) + 1
|
||||
|
||||
target:delStatusEffect(xi.effect.MAGIC_ATK_BOOST)
|
||||
target:delStatusEffect(xi.effect.MAGIC_DEF_BOOST)
|
||||
target:addStatusEffect(xi.effect.MAGIC_ATK_BOOST, { power = buffvalue, duration = duration, origin = pet })
|
||||
target:addStatusEffect(xi.effect.MAGIC_DEF_BOOST, { power = 14 - buffvalue, duration = duration, origin = pet })
|
||||
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.JA_RECEIVES_MAB_MDB)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_RECEIVES_MAB_MDB_2)
|
||||
end
|
||||
|
||||
return 0
|
||||
end)
|
||||
|
||||
return m
|
||||
110
modules/era/lua/actions/abilities/pets/attachments/analyzer.lua
Normal file
110
modules/era/lua/actions/abilities/pets/attachments/analyzer.lua
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
-----------------------------------
|
||||
-- Analyzer (Pre 2012)
|
||||
-- Reduces damage taken from repeated TP moves by 10%, with an additional 10% per Earth Maneuver.
|
||||
-- Resets after a new skill is used.
|
||||
-- Was changed March 27th, 2012 to analyze multiple TP moves based off earth maneuvers, with a 40% damage reduction.
|
||||
-- NOTE: This module touches both the attachment, and the combat utility. Both are needed for this attachment to function correctly.
|
||||
-- https://wiki.ffo.jp/html/10746.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'era_analyzer'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
-----------------------------------
|
||||
-- Attachment Module
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onEquip', function(pet, attachment)
|
||||
-- Analyzed skills do not carry over between zones, onEquip is called when rebuilding the automaton after zoning.
|
||||
pet:setLocalVar('analyzedSkill1', 0)
|
||||
|
||||
pet:addListener('WEAPONSKILL_TAKE', 'ANALYZER_WEAPONSKILL_TAKE', function(mob, target, skill, tp, action)
|
||||
local analyzerModifier = target:getMod(xi.mod.AUTO_ANALYZER)
|
||||
local incomingSkill = skill:getID()
|
||||
|
||||
-- If Analyzer modifier is 0, return. (Should be impossible since the attachment wouldn't be equipped, but just in case.)
|
||||
if analyzerModifier <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local analyzedSkill = target:getLocalVar('analyzedSkill1')
|
||||
|
||||
-- If the incoming skill is the one we have already analyzed, return.
|
||||
if incomingSkill == analyzedSkill then
|
||||
return
|
||||
end
|
||||
|
||||
-- If the incoming skill is different from the analyzed skill, update the analyzed skill ID.
|
||||
if incomingSkill ~= analyzedSkill then
|
||||
target:setLocalVar('analyzedSkill1', incomingSkill)
|
||||
end
|
||||
end)
|
||||
|
||||
xi.automaton.onAttachmentEquip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onUnequip', function(pet, attachment)
|
||||
-- Clear analyzed skill on unequip, and remove the listener.
|
||||
pet:setLocalVar('analyzedSkill1', 0)
|
||||
|
||||
pet:removeListener('ANALYZER_WEAPONSKILL_TAKE')
|
||||
|
||||
xi.automaton.onAttachmentUnequip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onManeuverGain', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onManeuverLose', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onUpdate', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Combat Utility Override
|
||||
-----------------------------------
|
||||
m:addOverride('utils.handleAutomatonAutoAnalyzer', function(actor, skill, damage)
|
||||
local analyzerModifier = actor:getMod(xi.mod.AUTO_ANALYZER)
|
||||
|
||||
-- If no Analyzer equipped, return unmodified damage.
|
||||
if analyzerModifier <= 0 then
|
||||
return damage
|
||||
end
|
||||
|
||||
local automatonId = actor:getID()
|
||||
|
||||
-- If we can't track this automaton, return unmodified damage.
|
||||
if not automatonId then
|
||||
return damage
|
||||
end
|
||||
|
||||
local automatonMaster = actor:getMaster()
|
||||
|
||||
-- If we can't get the master of this automaton, return unmodified damage.
|
||||
if not automatonMaster then
|
||||
return damage
|
||||
end
|
||||
|
||||
local incomingSkill = skill:getID()
|
||||
local analyzedSkill = actor:getLocalVar('analyzedSkill1')
|
||||
|
||||
-- If the incoming skill is the same ID as the analyzed skill, apply the Analyzer damage reduction and return.
|
||||
if incomingSkill == analyzedSkill then
|
||||
local earthManeuvers = automatonMaster:countEffect(xi.effect.EARTH_MANEUVER)
|
||||
local damageReduction = 10 + 10 * earthManeuvers
|
||||
|
||||
return math.floor(damage * (100 - damageReduction) / 100)
|
||||
end
|
||||
|
||||
-- If we somehow make it here, return unmodified damage.
|
||||
return damage
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
-----------------------------------
|
||||
-- Flame Holder
|
||||
-- Reverts Flame Holder to its pre-2015 functionality - Where it consumed Fire Maneuvers on skill execution.
|
||||
-- Flame Holder Bonus increased on August 5th, 2015.
|
||||
-- Changed to no longer consume Fire Maneuvers on August 6th, 2019.
|
||||
-- Source : https://wiki.ffo.jp/html/11183.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_flame_holder'
|
||||
|
||||
if xi.module.isContentEnabled('SOA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
local validSkills = set
|
||||
{
|
||||
xi.mobSkill.ARCUBALLISTA_AUTOMATON,
|
||||
xi.mobSkill.ARMOR_PIERCER_AUTOMATON,
|
||||
xi.mobSkill.ARMOR_SHATTERER_AUTOMATON,
|
||||
xi.mobSkill.BONE_CRUSHER_AUTOMATON,
|
||||
xi.mobSkill.CANNIBAL_BLADE_AUTOMATON,
|
||||
xi.mobSkill.CHIMERA_RIPPER_AUTOMATON,
|
||||
xi.mobSkill.DAZE_AUTOMATON,
|
||||
xi.mobSkill.KNOCKOUT_AUTOMATON,
|
||||
xi.mobSkill.MAGIC_MORTAR_AUTOMATON,
|
||||
xi.mobSkill.SLAPSTICK_AUTOMATON,
|
||||
xi.mobSkill.STRING_CLIPPER_AUTOMATON,
|
||||
xi.mobSkill.STRING_SHREDDER_AUTOMATON,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onEquip', function(pet, attachment)
|
||||
pet:addListener('WEAPONSKILL_STATE_ENTER', 'AUTO_FLAME_HOLDER_START', function(automaton, skillId)
|
||||
-- Not a valid skill for Flame Holder
|
||||
if not validSkills[skillId] then
|
||||
return
|
||||
end
|
||||
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
-- Fetch the amount of active Fire Maneuvers on weaponskill state entry.
|
||||
local fireManeuvers = master:countEffect(xi.effect.FIRE_MANEUVER)
|
||||
|
||||
-- No Fire Maneuvers
|
||||
if fireManeuvers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Set the WEAPONSKILL_DAMAGE_BASE mod to 125% / 150% / 175% based on the number of Fire Maneuvers active.
|
||||
local flameHolderAmount = 100 + 25 * fireManeuvers
|
||||
|
||||
automaton:setLocalVar('fireManeuvers', fireManeuvers)
|
||||
automaton:setLocalVar('flameHolderAmount', flameHolderAmount)
|
||||
automaton:addMod(xi.mod.WEAPONSKILL_DAMAGE_BASE, flameHolderAmount)
|
||||
end)
|
||||
|
||||
pet:addListener('WEAPONSKILL_STATE_EXIT', 'AUTO_FLAME_HOLDER_END', function(automaton, skillId, wasExecuted)
|
||||
local flameHolderAmount = automaton:getLocalVar('flameHolderAmount')
|
||||
|
||||
-- If no Flame Holder bonus is active, do nothing.
|
||||
if flameHolderAmount == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local fireManeuvers = automaton:getLocalVar('fireManeuvers')
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
-- Consume all Fire Maneuvers on execution.
|
||||
for i = 1, fireManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.FIRE_MANEUVER)
|
||||
end
|
||||
|
||||
-- Remove the Flame Holder bonus and reset local variables.
|
||||
automaton:delMod(xi.mod.WEAPONSKILL_DAMAGE_BASE, flameHolderAmount)
|
||||
automaton:setLocalVar('flameHolderAmount', 0)
|
||||
automaton:setLocalVar('fireManeuvers', 0)
|
||||
end)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onUnequip', function(pet, attachment)
|
||||
local amount = pet:getLocalVar('flameHolderAmount')
|
||||
|
||||
-- Should be nearly impossible, but just in case.
|
||||
if amount ~= 0 then
|
||||
pet:delMod(xi.mod.WEAPONSKILL_DAMAGE_BASE, amount)
|
||||
end
|
||||
|
||||
pet:setLocalVar('flameHolderAmount', 0)
|
||||
pet:setLocalVar('fireManeuvers', 0)
|
||||
pet:removeListener('AUTO_FLAME_HOLDER_START')
|
||||
pet:removeListener('AUTO_FLAME_HOLDER_END')
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onManeuverGain', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onManeuverLose', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onUpdate', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
-----------------------------------
|
||||
-- Ice Maker
|
||||
-- Reverts Ice Maker to its pre-2015 functionality - Where it consumed Ice Maneuvers on skill execution.
|
||||
-- Icemaker MAB Coefficients increased on August 5th, 2015.
|
||||
-- Changed to no longer consume Ice Maneuvers on August 6th, 2019.
|
||||
-- Source : https://wiki.ffo.jp/html/11198.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_ice_maker'
|
||||
|
||||
if xi.module.isContentEnabled('SOA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onEquip', function(pet, attachment)
|
||||
pet:addListener('MAGIC_START', 'AUTO_ICE_MAKER_START', function(automaton, skillId)
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
local iceManeuvers = master:countEffect(xi.effect.ICE_MANEUVER)
|
||||
|
||||
if iceManeuvers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local iceMakerAmount = 20 * iceManeuvers
|
||||
|
||||
automaton:setLocalVar('iceManeuvers', iceManeuvers)
|
||||
automaton:setLocalVar('iceMakerAmount', iceMakerAmount)
|
||||
automaton:addMod(xi.mod.AUTO_MAB_COEFFICIENT, iceMakerAmount)
|
||||
end)
|
||||
|
||||
pet:addListener('MAGIC_STATE_EXIT', 'AUTO_ICE_MAKER_END', function(automaton, skillId, wasExecuted)
|
||||
local iceMakerAmount = automaton:getLocalVar('iceMakerAmount')
|
||||
|
||||
-- If no Ice Maker bonus, do nothing.
|
||||
if iceMakerAmount == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local iceManeuvers = automaton:getLocalVar('iceManeuvers')
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
-- Consume all Ice Maneuvers on magic state exit.
|
||||
for i = 1, iceManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.ICE_MANEUVER)
|
||||
end
|
||||
|
||||
automaton:delMod(xi.mod.AUTO_MAB_COEFFICIENT, iceMakerAmount)
|
||||
automaton:setLocalVar('iceMakerAmount', 0)
|
||||
automaton:setLocalVar('iceManeuvers', 0)
|
||||
end)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onUnequip', function(pet, attachment)
|
||||
local amount = pet:getLocalVar('iceMakerAmount')
|
||||
|
||||
if amount ~= 0 then
|
||||
pet:delMod(xi.mod.AUTO_MAB_COEFFICIENT, amount)
|
||||
end
|
||||
|
||||
pet:setLocalVar('iceMakerAmount', 0)
|
||||
pet:setLocalVar('iceManeuvers', 0)
|
||||
pet:removeListener('AUTO_ICE_MAKER_START')
|
||||
pet:removeListener('AUTO_ICE_MAKER_END')
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onManeuverGain', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onManeuverLose', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onUpdate', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,552 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Attachment module
|
||||
-- Recreates attachment effects in the WoTG Era.
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
require('scripts/globals/automaton')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'attachments'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
-- Reduces Enmity boost from Strobe : https://wiki.ffo.jp/html/8610.html
|
||||
-- Reduces Store TP from Inhibitor : https://wiki.ffo.jp/html/8625.html
|
||||
-- Changes Armor Plate and Armor Plate II to Defense instead of PDT : https://wiki.ffo.jp/html/9070.html
|
||||
-- Adds a Ranged Attack Penalty to Drum Magazine. : https://wiki.ffo.jp/html/8882.html
|
||||
-- Changes Turbo Charger Haste to Gear Haste instead of Magic : https://wiki.ffo.jp/html/8627.html
|
||||
-- Adds Burden to Tactical Processor : https://wiki.ffo.jp/html/13527.html
|
||||
-- Reduces scaling from Volt Gun : https://wiki.ffo.jp/html/8752.html
|
||||
-- Reduces Burden Decay From Heatsink : https://wiki.ffo.jp/html/8629.html
|
||||
-- Reduces the potency of Steam Jackets Damage Reduction : https://wiki.ffo.jp/html/15352.html
|
||||
xi.automaton.attachmentModifiers['strobe' ] = { { modifier = xi.mod.ENMITY, values = { 5, 15, 25, 40 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['inhibitor' ] = { { modifier = xi.mod.STORETP, values = { 5, 10, 15, 20 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['armor_plate' ] = { { modifier = xi.mod.DEFP, values = { 10, 15, 20, 25 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['armor_plate_ii' ] = { { modifier = xi.mod.DEFP, values = { 20, 25, 30, 35 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['drum_magazine' ] = { { modifier = xi.mod.AUTO_RANGED_DELAY, values = { 2, 4, 6, 8 }, opticFiber = false },
|
||||
{ modifier = xi.mod.RACC, values = { -15, -30, -50, -75 }, opticFiber = false }, }
|
||||
xi.automaton.attachmentModifiers['flame_holder' ] = { { modifier = xi.mod.WEAPONSKILL_DAMAGE_BASE, values = { 0, 125, 150, 175 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['ice_maker' ] = { { modifier = xi.mod.AUTO_MAB_COEFFICIENT, values = { 0, 20, 40, 60 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['turbo_charger' ] = { { modifier = xi.mod.HASTE_GEAR, values = { 500, 1500, 2000, 2500 }, opticFiber = true }, }
|
||||
xi.automaton.attachmentModifiers['tactical_processor'] = { { modifier = xi.mod.AUTO_DECISION_DELAY, values = { 50, 70, 85, 115 }, opticFiber = false },
|
||||
{ modifier = xi.mod.OVERLOAD_THRESH, values = { -5, -5, -5, -5 }, opticFiber = false }, }
|
||||
xi.automaton.attachmentModifiers['volt_gun' ] = { { modifier = xi.mod.VOLT_GUN_POTENCY, values = { 0, 0, 0, 0 }, opticFiber = false }, }
|
||||
xi.automaton.attachmentModifiers['heatsink' ] = { { modifier = xi.mod.BURDEN_DECAY, values = { 1, 1, 1, 1 }, opticFiber = false }, }
|
||||
xi.automaton.attachmentModifiers['steam_jacket' ] = { { modifier = xi.mod.AUTO_STEAM_JACKET_REDUCTION, values = { 25, 35, 40, 60 }, opticFiber = true }, }
|
||||
|
||||
-- Reduces potency of Auto Repair Kit II and removed level based scaling from Mana Tank : https://wiki.ffo.jp/html/19739.html
|
||||
xi.automaton.repairKit.data['auto-repair_kit_ii' ] = { id = 196, hpBoost = 2, regenBase = { 0, 2, 3, 4 }, regenMultiplier = { 0, 0.4, 0.6, 0.8 } }
|
||||
xi.automaton.manaTank.data ['mana_tank' ] = { id = 225, mpBoost = 1, refreshBase = { 0, 1, 2, 3 }, refreshMultiplier = { 0, 0.0, 0.0, 0.0 } }
|
||||
xi.automaton.manaTank.data ['mana_tank_ii' ] = { id = 228, mpBoost = 2, refreshBase = { 0, 2, 3, 4 }, refreshMultiplier = { 0, 0.0, 0.0, 0.0 } }
|
||||
|
||||
-----------------------------------
|
||||
-- Flame Holder - Reduces Flame Holder Scaling, and consumes all Fire Maneuvers on weaponskill execution. https://wiki.ffo.jp/html/11183.html
|
||||
-----------------------------------
|
||||
local validFlameHolderSkills = set
|
||||
{
|
||||
xi.mobSkill.ARCUBALLISTA_AUTOMATON,
|
||||
xi.mobSkill.ARMOR_PIERCER_AUTOMATON,
|
||||
xi.mobSkill.ARMOR_SHATTERER_AUTOMATON,
|
||||
xi.mobSkill.BONE_CRUSHER_AUTOMATON,
|
||||
xi.mobSkill.CANNIBAL_BLADE_AUTOMATON,
|
||||
xi.mobSkill.CHIMERA_RIPPER_AUTOMATON,
|
||||
xi.mobSkill.DAZE_AUTOMATON,
|
||||
xi.mobSkill.KNOCKOUT_AUTOMATON,
|
||||
xi.mobSkill.MAGIC_MORTAR_AUTOMATON,
|
||||
xi.mobSkill.SLAPSTICK_AUTOMATON,
|
||||
xi.mobSkill.STRING_CLIPPER_AUTOMATON,
|
||||
xi.mobSkill.STRING_SHREDDER_AUTOMATON,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onEquip', function(pet, attachment)
|
||||
pet:addListener('WEAPONSKILL_STATE_EXIT', 'AUTO_FLAME_HOLDER_END', function(automaton, skillId, wasExecuted)
|
||||
if not validFlameHolderSkills[skillId] then
|
||||
return
|
||||
end
|
||||
|
||||
if not wasExecuted then
|
||||
return
|
||||
end
|
||||
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
-- Consume all Fire Maneuvers on weaponskill execution.
|
||||
local fireManeuvers = master:countEffect(xi.effect.FIRE_MANEUVER)
|
||||
|
||||
for i = 1, fireManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.FIRE_MANEUVER)
|
||||
end
|
||||
|
||||
master:updateAttachments()
|
||||
end)
|
||||
|
||||
xi.automaton.onAttachmentEquip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.flame_holder.onUnequip', function(pet, attachment)
|
||||
xi.automaton.onAttachmentUnequip(pet, attachment)
|
||||
pet:removeListener('AUTO_FLAME_HOLDER_END')
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Ice Maker - Reduces Magic Attack Bonus from Ice Maker, and consumes all Ice Maneuvers on magic attack execution. https://wiki.ffo.jp/html/11198.html
|
||||
-----------------------------------
|
||||
local validIceMakerSpells = set
|
||||
{
|
||||
xi.magic.spell.FIRE,
|
||||
xi.magic.spell.FIRE_II,
|
||||
xi.magic.spell.FIRE_III,
|
||||
xi.magic.spell.FIRE_IV,
|
||||
xi.magic.spell.FIRE_V,
|
||||
xi.magic.spell.BLIZZARD,
|
||||
xi.magic.spell.BLIZZARD_II,
|
||||
xi.magic.spell.BLIZZARD_III,
|
||||
xi.magic.spell.BLIZZARD_IV,
|
||||
xi.magic.spell.BLIZZARD_V,
|
||||
xi.magic.spell.AERO,
|
||||
xi.magic.spell.AERO_II,
|
||||
xi.magic.spell.AERO_III,
|
||||
xi.magic.spell.AERO_IV,
|
||||
xi.magic.spell.AERO_V,
|
||||
xi.magic.spell.STONE,
|
||||
xi.magic.spell.STONE_II,
|
||||
xi.magic.spell.STONE_III,
|
||||
xi.magic.spell.STONE_IV,
|
||||
xi.magic.spell.STONE_V,
|
||||
xi.magic.spell.THUNDER,
|
||||
xi.magic.spell.THUNDER_II,
|
||||
xi.magic.spell.THUNDER_III,
|
||||
xi.magic.spell.THUNDER_IV,
|
||||
xi.magic.spell.THUNDER_V,
|
||||
xi.magic.spell.WATER,
|
||||
xi.magic.spell.WATER_II,
|
||||
xi.magic.spell.WATER_III,
|
||||
xi.magic.spell.WATER_IV,
|
||||
xi.magic.spell.WATER_V,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onEquip', function(pet, attachment)
|
||||
pet:addListener('MAGIC_USE', 'AUTO_ICE_MAKER_USE', function(automaton, target, spell, action)
|
||||
if not validIceMakerSpells[spell:getID()] then
|
||||
return
|
||||
end
|
||||
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
local iceManeuvers = master:countEffect(xi.effect.ICE_MANEUVER)
|
||||
|
||||
for i = 1, iceManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.ICE_MANEUVER)
|
||||
end
|
||||
|
||||
master:updateAttachments()
|
||||
end)
|
||||
|
||||
xi.automaton.onAttachmentEquip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.ice_maker.onUnequip', function(pet, attachment)
|
||||
xi.automaton.onAttachmentUnequip(pet, attachment)
|
||||
pet:removeListener('AUTO_ICE_MAKER_USE')
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Replicator - Reduces amount of absorbs granted by Replicator, and changes them to Blink from Utsusemi. Also consumes Wind Maneuvers. https://wiki.ffo.jp/html/12225.html
|
||||
-----------------------------------
|
||||
local shadowTable =
|
||||
{
|
||||
[1] = 2,
|
||||
[2] = 3,
|
||||
[3] = 4,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.replicator.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.replicator.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local windManeuvers = xi.automaton.getManeuverCount(master, master:countEffect(xi.effect.WIND_MANEUVER))
|
||||
local shadows = shadowTable[windManeuvers]
|
||||
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 60)
|
||||
|
||||
for i = 1, windManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.WIND_MANEUVER)
|
||||
end
|
||||
|
||||
master:updateAttachments()
|
||||
|
||||
if
|
||||
shadows and
|
||||
target:addStatusEffect(xi.effect.BLINK, { power = shadows, duration = 300, origin = automaton })
|
||||
then
|
||||
skill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT)
|
||||
else
|
||||
skill:setMsg(xi.msg.basic.SKILL_NO_EFFECT)
|
||||
end
|
||||
|
||||
return xi.effect.BLINK
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Shock Absorber - Reduces the potency of the stoneskin effect and removes scaling. https://wiki.ffo.jp/html/12927.html
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.shock_absorber.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.shock_absorber.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 180)
|
||||
|
||||
if target:addStatusEffect(xi.effect.STONESKIN, { power = 100, duration = 180, origin = automaton, tier = 4 }) then
|
||||
skill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT)
|
||||
else
|
||||
skill:setMsg(xi.msg.basic.SKILL_NO_EFFECT)
|
||||
end
|
||||
|
||||
return xi.effect.STONESKIN
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Shield Bash - Removes gaurunteed hit chance while Hammermill is equipped. https://wiki.ffo.jp/html/12156.html
|
||||
-----------------------------------
|
||||
local shieldBashSlowTable =
|
||||
{
|
||||
[1] = { tier = 4, duration = 30 },
|
||||
[2] = { tier = 5, duration = 50 },
|
||||
[3] = { tier = 6, duration = 70 },
|
||||
}
|
||||
|
||||
local function applyHammermillSlow(automaton, target, skill, master)
|
||||
local power = automaton:getMod(xi.mod.AUTO_SHIELD_BASH_SLOW) * 100
|
||||
if power <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local slowTier = shieldBashSlowTable[master and xi.automaton.getManeuverCount(master, master:countEffect(xi.effect.EARTH_MANEUVER)) or 0]
|
||||
|
||||
local params =
|
||||
{
|
||||
[1] = { effectId = xi.effect.SLOW, power = power, duration = slowTier.duration, tier = slowTier.tier },
|
||||
}
|
||||
|
||||
xi.combat.action.executeMobskillStatusEffect(automaton, target, skill, params, { messageBypass = true })
|
||||
end
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.shield_bash.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Hammermill
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.shield_bash.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getWeaponDmg()
|
||||
params.numHits = utils.clamp(1 + xi.automaton.getExtraHits(automaton, 1), 1, 8)
|
||||
params.fTP = { 1.0, 1.0, 1.0 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.BLUNT
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
local hammermillEquipped = automaton:hasAttachmentSet(xi.item.HAMMERMILL_ATTACHMENT)
|
||||
|
||||
if hammermillEquipped then
|
||||
local shieldBashBonus = 1.0 + automaton:getMod(xi.mod.SHIELD_BASH) / 100
|
||||
|
||||
params.fTP =
|
||||
{
|
||||
params.fTP[1] * shieldBashBonus,
|
||||
params.fTP[2] * shieldBashBonus,
|
||||
params.fTP[3] * shieldBashBonus,
|
||||
}
|
||||
end
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
|
||||
xi.mobskills.mobStatusEffectMove(automaton, target, xi.effect.STUN, 1, 0, 6)
|
||||
|
||||
if hammermillEquipped then
|
||||
applyHammermillSlow(automaton, target, skill, master)
|
||||
end
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Analyzer - Caps the amount of skills that can be analyzed to 1. https://wiki.ffo.jp/html/10746.html
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onEquip', function(pet, attachment)
|
||||
pet:setLocalVar('analyzedSkill1', 0)
|
||||
|
||||
pet:addListener('WEAPONSKILL_TAKE', 'ANALYZER_WEAPONSKILL_TAKE', function(mob, target, skill, tp, action)
|
||||
local analyzerModifier = target:getMod(xi.mod.AUTO_ANALYZER)
|
||||
local incomingSkill = skill:getID()
|
||||
|
||||
if analyzerModifier <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local analyzedSkill = target:getLocalVar('analyzedSkill1')
|
||||
|
||||
if incomingSkill == analyzedSkill then
|
||||
return
|
||||
end
|
||||
|
||||
if incomingSkill ~= analyzedSkill then
|
||||
target:setLocalVar('analyzedSkill1', incomingSkill)
|
||||
end
|
||||
end)
|
||||
|
||||
xi.automaton.onAttachmentEquip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onUnequip', function(pet, attachment)
|
||||
pet:setLocalVar('analyzedSkill1', 0)
|
||||
|
||||
pet:removeListener('ANALYZER_WEAPONSKILL_TAKE')
|
||||
|
||||
xi.automaton.onAttachmentUnequip(pet, attachment)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onManeuverGain', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onManeuverLose', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.attachments.analyzer.onUpdate', function(pet, attachment, maneuvers)
|
||||
end)
|
||||
|
||||
m:addOverride('utils.handleAutomatonAutoAnalyzer', function(actor, skill, damage)
|
||||
local analyzerModifier = actor:getMod(xi.mod.AUTO_ANALYZER)
|
||||
|
||||
if analyzerModifier <= 0 then
|
||||
return damage
|
||||
end
|
||||
|
||||
local automatonId = actor:getID()
|
||||
|
||||
if not automatonId then
|
||||
return damage
|
||||
end
|
||||
|
||||
local automatonMaster = actor:getMaster()
|
||||
|
||||
if not automatonMaster then
|
||||
return damage
|
||||
end
|
||||
|
||||
local incomingSkill = skill:getID()
|
||||
local analyzedSkill = actor:getLocalVar('analyzedSkill1')
|
||||
|
||||
if incomingSkill == analyzedSkill then
|
||||
local earthManeuvers = xi.automaton.getManeuverCount(automatonMaster, automatonMaster:countEffect(xi.effect.EARTH_MANEUVER))
|
||||
local damageReduction = 10 + 10 * earthManeuvers
|
||||
|
||||
return math.floor(damage * (100 - damageReduction) / 100)
|
||||
end
|
||||
|
||||
return damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Eraser - Changes Eraser to consume all Maneuvers on activation. https://wiki.ffo.jp/html/5365.html
|
||||
-----------------------------------
|
||||
local maneuvers =
|
||||
{
|
||||
xi.effect.FIRE_MANEUVER,
|
||||
xi.effect.ICE_MANEUVER,
|
||||
xi.effect.WIND_MANEUVER,
|
||||
xi.effect.EARTH_MANEUVER,
|
||||
xi.effect.THUNDER_MANEUVER,
|
||||
xi.effect.WATER_MANEUVER,
|
||||
xi.effect.LIGHT_MANEUVER,
|
||||
xi.effect.DARK_MANEUVER,
|
||||
}
|
||||
|
||||
local function removeAllManeuvers(master)
|
||||
-- Era Eraser consumes all active maneuvers, not just Light Maneuvers.
|
||||
for _, maneuverId in ipairs(maneuvers) do
|
||||
for _ = 1, master:countEffect(maneuverId) do
|
||||
master:delStatusEffectSilent(maneuverId)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local removables =
|
||||
{
|
||||
-- Songs
|
||||
xi.effect.ELEGY,
|
||||
xi.effect.REQUIEM,
|
||||
xi.effect.THRENODY,
|
||||
|
||||
-- Enfeebling
|
||||
xi.effect.BLINDNESS,
|
||||
xi.effect.PARALYSIS,
|
||||
xi.effect.SILENCE,
|
||||
xi.effect.POISON,
|
||||
xi.effect.CURSE_I,
|
||||
xi.effect.CURSE_II,
|
||||
xi.effect.DISEASE,
|
||||
xi.effect.PLAGUE,
|
||||
xi.effect.WEIGHT,
|
||||
xi.effect.BIND,
|
||||
xi.effect.ADDLE,
|
||||
xi.effect.SLOW,
|
||||
xi.effect.PETRIFICATION,
|
||||
|
||||
-- DoTs
|
||||
xi.effect.BIO,
|
||||
xi.effect.DIA,
|
||||
xi.effect.BURN,
|
||||
xi.effect.FROST,
|
||||
xi.effect.CHOKE,
|
||||
xi.effect.RASP,
|
||||
xi.effect.SHOCK,
|
||||
xi.effect.DROWN,
|
||||
|
||||
-- Main Stat Downs
|
||||
xi.effect.STR_DOWN,
|
||||
xi.effect.DEX_DOWN,
|
||||
xi.effect.VIT_DOWN,
|
||||
xi.effect.AGI_DOWN,
|
||||
xi.effect.INT_DOWN,
|
||||
xi.effect.MND_DOWN,
|
||||
xi.effect.CHR_DOWN,
|
||||
|
||||
-- Combat Stat Downs
|
||||
xi.effect.ACCURACY_DOWN,
|
||||
xi.effect.ATTACK_DOWN,
|
||||
xi.effect.EVASION_DOWN,
|
||||
xi.effect.DEFENSE_DOWN,
|
||||
|
||||
-- Magic Stat Downs
|
||||
xi.effect.MAGIC_ACC_DOWN,
|
||||
xi.effect.MAGIC_ATK_DOWN,
|
||||
xi.effect.MAGIC_EVASION_DOWN,
|
||||
xi.effect.MAGIC_DEF_DOWN,
|
||||
|
||||
-- HP/MP/TP Stat Downs
|
||||
xi.effect.MAX_TP_DOWN,
|
||||
xi.effect.MAX_MP_DOWN,
|
||||
xi.effect.MAX_HP_DOWN,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.eraser.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.eraser.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 30)
|
||||
|
||||
local lightManeuvers = xi.automaton.getManeuverCount(master, master:countEffect(xi.effect.LIGHT_MANEUVER))
|
||||
local effectsRemoved = 0
|
||||
|
||||
for _, effectId in ipairs(removables) do
|
||||
if target:hasStatusEffect(effectId) then
|
||||
target:delStatusEffectSilent(effectId)
|
||||
effectsRemoved = effectsRemoved + 1
|
||||
|
||||
if effectsRemoved >= lightManeuvers then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
removeAllManeuvers(master)
|
||||
master:updateAttachments()
|
||||
|
||||
if effectsRemoved > 0 then
|
||||
skill:setMsg(xi.msg.basic.DISAPPEAR_NUM)
|
||||
else
|
||||
skill:setMsg(xi.msg.basic.USES)
|
||||
end
|
||||
|
||||
return effectsRemoved
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Economizer - Changes Economizer to consume all Dark Maneuvers on activation. : https://wiki.ffo.jp/html/10435.html
|
||||
-----------------------------------
|
||||
local activationThresholds =
|
||||
{
|
||||
[0] = 30,
|
||||
[1] = 40,
|
||||
[2] = 50,
|
||||
[3] = 60,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.economizer.onEquip', function(pet)
|
||||
pet:addListener('AUTOMATON_ATTACHMENT_CHECK', 'ATTACHMENT_ECONOMIZER', function(automaton, target)
|
||||
-- If Economizer is still on cooldown, do nothing.
|
||||
if automaton:hasRecast(xi.recast.ABILITY, xi.mobSkill.ECONOMIZER_AUTOMATON) then
|
||||
return
|
||||
end
|
||||
|
||||
local master = automaton:getMaster()
|
||||
|
||||
if not master then
|
||||
return
|
||||
end
|
||||
|
||||
local darkManeuvers = master:countEffect(xi.effect.DARK_MANEUVER)
|
||||
|
||||
if darkManeuvers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local maxMP = automaton:getMaxMP()
|
||||
|
||||
-- If this automaton has no MP, do nothing.
|
||||
if maxMP == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local mpPercent = automaton:getMPP()
|
||||
local mpThreshold = activationThresholds[darkManeuvers] or 30
|
||||
|
||||
-- If the automaton's MP is above the threshold, do nothing.
|
||||
if mpPercent > mpThreshold then
|
||||
return
|
||||
end
|
||||
|
||||
automaton:useMobAbility(xi.mobSkill.ECONOMIZER_AUTOMATON, automaton)
|
||||
end)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.economizer.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 180)
|
||||
|
||||
local darkManeuvers = master:countEffect(xi.effect.DARK_MANEUVER)
|
||||
local mpRecovered = math.floor(automaton:getMaxMP() * 0.2 * darkManeuvers)
|
||||
|
||||
for _ = 1, darkManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.DARK_MANEUVER)
|
||||
end
|
||||
|
||||
master:updateAttachments()
|
||||
|
||||
skill:setMsg(xi.msg.basic.SKILL_RECOVERS_MP)
|
||||
|
||||
return automaton:addMP(mpRecovered)
|
||||
end)
|
||||
|
||||
return m
|
||||
129
modules/era/lua/actions/abilities/pets/automaton/eraser.lua
Normal file
129
modules/era/lua/actions/abilities/pets/automaton/eraser.lua
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
-----------------------------------
|
||||
-- Eraser (Pre-2011)
|
||||
-- Removes up to 3 status effects from the Automaton or its Master based on the number of Light Maneuvers active.
|
||||
-- Consumes all maneuvers on use.
|
||||
-- Eraser cannot remove Venom, Death Sentence, Charm or Gradual Petrification.
|
||||
-- Prioritizes removing effects from the Automaton over the Master.
|
||||
-- Updated to consume only Light Maneuvers on December 15th, 2011.
|
||||
-- Updated to consume no maneuvers on March 11th, 2019.
|
||||
-- https://wiki.ffo.jp/html/5365.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'era_eraser'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
local maneuvers =
|
||||
{
|
||||
xi.effect.FIRE_MANEUVER,
|
||||
xi.effect.ICE_MANEUVER,
|
||||
xi.effect.WIND_MANEUVER,
|
||||
xi.effect.EARTH_MANEUVER,
|
||||
xi.effect.THUNDER_MANEUVER,
|
||||
xi.effect.WATER_MANEUVER,
|
||||
xi.effect.LIGHT_MANEUVER,
|
||||
xi.effect.DARK_MANEUVER,
|
||||
}
|
||||
|
||||
local removables =
|
||||
{
|
||||
-- Songs
|
||||
xi.effect.ELEGY,
|
||||
xi.effect.REQUIEM,
|
||||
xi.effect.THRENODY,
|
||||
|
||||
-- Enfeebling
|
||||
xi.effect.BLINDNESS,
|
||||
xi.effect.PARALYSIS,
|
||||
xi.effect.SILENCE,
|
||||
xi.effect.POISON,
|
||||
xi.effect.CURSE_I,
|
||||
xi.effect.CURSE_II,
|
||||
xi.effect.DISEASE,
|
||||
xi.effect.PLAGUE,
|
||||
xi.effect.WEIGHT,
|
||||
xi.effect.BIND,
|
||||
xi.effect.ADDLE,
|
||||
xi.effect.SLOW,
|
||||
xi.effect.PETRIFICATION,
|
||||
|
||||
-- DoTs
|
||||
xi.effect.BIO,
|
||||
xi.effect.DIA,
|
||||
xi.effect.BURN,
|
||||
xi.effect.FROST,
|
||||
xi.effect.CHOKE,
|
||||
xi.effect.RASP,
|
||||
xi.effect.SHOCK,
|
||||
xi.effect.DROWN,
|
||||
|
||||
-- Main Stat Downs
|
||||
xi.effect.STR_DOWN,
|
||||
xi.effect.DEX_DOWN,
|
||||
xi.effect.VIT_DOWN,
|
||||
xi.effect.AGI_DOWN,
|
||||
xi.effect.INT_DOWN,
|
||||
xi.effect.MND_DOWN,
|
||||
xi.effect.CHR_DOWN,
|
||||
|
||||
-- Combat Stat Downs
|
||||
xi.effect.ACCURACY_DOWN,
|
||||
xi.effect.ATTACK_DOWN,
|
||||
xi.effect.EVASION_DOWN,
|
||||
xi.effect.DEFENSE_DOWN,
|
||||
|
||||
-- Magic Stat Downs
|
||||
xi.effect.MAGIC_ACC_DOWN,
|
||||
xi.effect.MAGIC_ATK_DOWN,
|
||||
xi.effect.MAGIC_EVASION_DOWN,
|
||||
xi.effect.MAGIC_DEF_DOWN,
|
||||
|
||||
-- HP/MP/TP Stat Downs
|
||||
xi.effect.MAX_TP_DOWN,
|
||||
xi.effect.MAX_MP_DOWN,
|
||||
xi.effect.MAX_HP_DOWN,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.eraser.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.eraser.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 30)
|
||||
|
||||
local lightManeuvers = master:countEffect(xi.effect.LIGHT_MANEUVER)
|
||||
local effectsRemoved = 0
|
||||
|
||||
for _, effectId in ipairs(removables) do
|
||||
if target:hasStatusEffect(effectId) then
|
||||
target:delStatusEffectSilent(effectId)
|
||||
effectsRemoved = effectsRemoved + 1
|
||||
|
||||
if effectsRemoved >= lightManeuvers then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, maneuverId in ipairs(maneuvers) do
|
||||
for _ = 1, master:countEffect(maneuverId) do
|
||||
master:delStatusEffectSilent(maneuverId)
|
||||
end
|
||||
end
|
||||
|
||||
if effectsRemoved > 0 then
|
||||
skill:setMsg(xi.msg.basic.DISAPPEAR_NUM)
|
||||
else
|
||||
skill:setMsg(xi.msg.basic.USES)
|
||||
end
|
||||
|
||||
return effectsRemoved
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
-----------------------------------
|
||||
-- Replicator (Pre-2011)
|
||||
-- Description : Applies Blink based on Wind Maneuvers when HP is below a certain threshold. Cooldown of 1 minute. Consumes all Wind Maneuvers on use.
|
||||
-- If Automaton has a Damage Gauge equipped, activation threshold is increased to 75% HP.
|
||||
-- Amount of images increased on December 15th, 2011.
|
||||
-- Changed from Blink to Copy Image on August 5th, 2015.
|
||||
-- Changed to not consume Wind Maneuvers on August 6th, 2019.
|
||||
-- https://wiki.ffo.jp/html/12225.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'era_replicator'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
local shadowTable =
|
||||
{
|
||||
[1] = 2,
|
||||
[2] = 3,
|
||||
[3] = 4,
|
||||
}
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.replicator.onAutomatonAbilityCheck', function(target, automaton, skill)
|
||||
return 0
|
||||
end)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.replicator.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local windManeuvers = master:countEffect(xi.effect.WIND_MANEUVER)
|
||||
local shadows = shadowTable[windManeuvers]
|
||||
|
||||
automaton:addRecast(xi.recast.ABILITY, skill:getID(), 60)
|
||||
|
||||
for i = 1, windManeuvers do
|
||||
master:delStatusEffectSilent(xi.effect.WIND_MANEUVER)
|
||||
end
|
||||
|
||||
if target:addStatusEffect(xi.effect.BLINK, { power = shadows, duration = 300, origin = automaton }) then
|
||||
skill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT)
|
||||
else
|
||||
skill:setMsg(xi.msg.basic.SKILL_NO_EFFECT)
|
||||
end
|
||||
|
||||
return xi.effect.BLINK
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Reverts Hastega to no longer have a duration based on summoning magic and reduces haste power
|
||||
-- Source: https://www.bg-wiki.com/ffxi/Version_Update_(04/08/2009)
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
|
||||
local moduleName = 'hastega'
|
||||
|
||||
if xi.module.isContentEnabled('WOTG') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
m:addOverride('xi.actions.abilities.pets.hastega.onPetAbility', function(target, pet, petskill, summoner, action)
|
||||
local duration = 180
|
||||
|
||||
xi.job_utils.summoner.onUseBloodPact(target, petskill, summoner, action)
|
||||
|
||||
-- Reverts Garuda's Hastega to use 102/1024 or 9.96%
|
||||
local typeEffect = xi.effect.HASTE
|
||||
if target:addStatusEffect(typeEffect, { power = 996, duration = duration, origin = pet }) then
|
||||
if target:getID() == action:getPrimaryTargetID() then
|
||||
petskill:setMsg(xi.msg.basic.SKILL_GAIN_EFFECT_2)
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_GAIN_EFFECT)
|
||||
end
|
||||
else
|
||||
petskill:setMsg(xi.msg.basic.JA_NO_EFFECT_2)
|
||||
return
|
||||
end
|
||||
|
||||
return typeEffect
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -145,11 +145,10 @@ m:addOverride('xi.actions.weaponskills.namas_arrow.onUseWeaponSkill', function(p
|
|||
params.overrideVE = 480
|
||||
params.rangedAccuracyBonus = 100
|
||||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doRangedWeaponskill(player, target, wsID, params, tp, action, primary)
|
||||
|
||||
-- Apply aftermath
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.RANGED, xi.aftermath.type.RELIC)
|
||||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doRangedWeaponskill(player, target, wsID, params, tp, action, primary)
|
||||
return tpHits, extraHits, criticalHit, damage
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,305 +0,0 @@
|
|||
-----------------------------------
|
||||
-- WoTG Era Automaton Weaponskills
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'wotg_automaton'
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
-----------------------------------
|
||||
-- Arcuballista
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.arcuballista.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = xi.automaton.getRangedBaseDamage(automaton)
|
||||
params.numHits = 1
|
||||
params.fTP = { 2.5, 3.0, 4.0 }
|
||||
params.dex_wSC = 0.30
|
||||
params.accuracyModifier = { 100, 100, 100 }
|
||||
params.attackType = xi.attackType.RANGED
|
||||
params.damageType = xi.damageType.PIERCING
|
||||
params.shadowBehavior = xi.mobskills.shadowBehavior.NUMSHADOWS_1
|
||||
params.skipParry = true
|
||||
params.skipGuard = true
|
||||
params.skipBlock = true
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobRangedMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Armor Piercer
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.armor_piercer.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = xi.automaton.getRangedBaseDamage(automaton)
|
||||
params.numHits = 1
|
||||
params.fTP = { 3.0, 3.5, 4.0 }
|
||||
params.dex_wSC = 0.30
|
||||
params.ignoreDefense = { 0.5, 0.5, 0.5 }
|
||||
params.accuracyModifier = { 100, 100, 100 }
|
||||
params.attackType = xi.attackType.RANGED
|
||||
params.damageType = xi.damageType.PIERCING
|
||||
params.shadowBehavior = xi.mobskills.shadowBehavior.NUMSHADOWS_1
|
||||
params.skipParry = true
|
||||
params.skipGuard = true
|
||||
params.skipBlock = true
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobRangedMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Bone Crusher
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.bone_crusher.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getWeaponDmg()
|
||||
params.numHits = utils.clamp(3 + xi.automaton.getExtraHits(automaton, 3), 1, 8)
|
||||
params.fTP = { 1.5, 1.5, 1.5 }
|
||||
params.vit_wSC = 0.30
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.BLUNT
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
if target:isUndead() then
|
||||
params.fTP = { 2.5, 2.5, 2.5 }
|
||||
end
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
|
||||
xi.mobskills.mobStatusEffectMove(automaton, target, xi.effect.STUN, 1, 0, 4)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Cannibal Blade
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.cannibal_blade.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getSkillLevel(xi.skill.AUTOMATON_MELEE) / 9.2
|
||||
params.numHits = 1
|
||||
params.fTP = { 11.0, 12.5, 14.0 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.SLASHING
|
||||
params.shadowBehavior = xi.mobskills.shadowBehavior.NUMSHADOWS_1
|
||||
params.guaranteedFirstHit = true
|
||||
params.skipFSTR = true
|
||||
params.skipPDIF = true
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
|
||||
if not target:isUndead() then
|
||||
automaton:addHP(info.damage)
|
||||
end
|
||||
end
|
||||
|
||||
-- Does not return TP.
|
||||
automaton:setTP(0)
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Chimera Ripper
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.chimera_ripper.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getWeaponDmg()
|
||||
params.numHits = utils.clamp(1 + xi.automaton.getExtraHits(automaton, 1), 1, 8)
|
||||
params.fTP = { 2.0, 2.5, 3.0 }
|
||||
params.str_wSC = 0.30
|
||||
params.accuracyModifier = { 100, 100, 100 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.SLASHING
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Daze
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.daze.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = xi.automaton.getRangedBaseDamage(automaton)
|
||||
params.numHits = 1
|
||||
params.fTP = { 5.0, 5.5, 6.0 }
|
||||
params.dex_wSC = 0.30
|
||||
params.accuracyModifier = { 150, 150, 150 }
|
||||
params.attackType = xi.attackType.RANGED
|
||||
params.damageType = xi.damageType.PIERCING
|
||||
params.shadowBehavior = xi.mobskills.shadowBehavior.NUMSHADOWS_1
|
||||
params.skipParry = true
|
||||
params.skipGuard = true
|
||||
params.skipBlock = true
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobRangedMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
|
||||
xi.mobskills.mobStatusEffectMove(automaton, target, xi.effect.STUN, 1, 0, 4)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Knockout
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.knockout.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.numHits = utils.clamp(1 + xi.automaton.getExtraHits(automaton, 1), 1, 8)
|
||||
params.fTP = { 4.0, 4.5, 5.0 }
|
||||
params.agi_wSC = 0.40
|
||||
params.accuracyModifier = { 50, 50, 50 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.BLUNT
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
|
||||
xi.mobskills.mobStatusEffectMove(automaton, target, xi.effect.EVASION_DOWN, 20, 0, 30)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Magic Mortar
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.magic_mortar.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getMaxHP() - automaton:getHP()
|
||||
params.fTP = { 0.50, 0.75, 1.00 }
|
||||
params.element = xi.element.NONE
|
||||
params.attackType = xi.attackType.MAGICAL
|
||||
params.damageType = xi.damageType.ELEMENTAL
|
||||
params.shadowBehavior = xi.mobskills.shadowBehavior.IGNORE_SHADOWS
|
||||
|
||||
-- Flame Holder multiplies the base damage of Magic Mortar. Gives a 25% boost at 3 Fire Maneuvers.
|
||||
local flameHolderModifier = 1.0 + (automaton:getMod(xi.mod.WEAPONSKILL_DAMAGE_BASE) - 100) / 1000
|
||||
|
||||
if flameHolderModifier > 1.0 then
|
||||
params.baseDamage = math.floor(params.baseDamage * flameHolderModifier)
|
||||
end
|
||||
|
||||
local info = xi.mobskills.mobMagicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- Slapstick
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.slapstick.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.numHits = utils.clamp(3 + xi.automaton.getExtraHits(automaton, 3), 1, 8)
|
||||
params.fTP = { 1.0, 1.0, 1.0 }
|
||||
params.str_wSC = 0.20
|
||||
params.dex_wSC = 0.20
|
||||
params.accuracyModifier = { 0, 30, 50 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.BLUNT
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
-----------------------------------
|
||||
-- String Clipper
|
||||
-----------------------------------
|
||||
m:addOverride('xi.actions.abilities.pets.automaton.string_clipper.onAutomatonAbility', function(target, automaton, skill, master, action)
|
||||
local params = {}
|
||||
|
||||
params.baseDamage = automaton:getWeaponDmg()
|
||||
params.numHits = utils.clamp(2 + xi.automaton.getExtraHits(automaton, 2), 1, 8)
|
||||
params.fTP = { 2.0, 2.0, 2.0 }
|
||||
params.str_wSC = 0.15
|
||||
params.dex_wSC = 0.15
|
||||
params.attackMultiplier = { 1.5, 1.5, 1.5 }
|
||||
params.accuracyModifier = { 0, 50, 100 }
|
||||
params.attackType = xi.attackType.PHYSICAL
|
||||
params.damageType = xi.damageType.SLASHING
|
||||
params.shadowBehavior = params.numHits
|
||||
|
||||
xi.automaton.applyFlameHolder(automaton, params.fTP)
|
||||
|
||||
local info = xi.mobskills.mobPhysicalMove(automaton, target, skill, action, params)
|
||||
|
||||
if xi.mobskills.processDamage(automaton, target, skill, action, info) then
|
||||
target:takeDamage(info.damage, automaton, info.attackType, info.damageType)
|
||||
end
|
||||
|
||||
return info.damage
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -37,7 +37,7 @@ m:addOverride('xi.actions.weaponskills.smash_axe.onUseWeaponSkill', function(pla
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
@ -63,7 +63,7 @@ m:addOverride('xi.actions.weaponskills.gale_axe.onUseWeaponSkill', function(play
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.CHOKE
|
||||
local actionElement = xi.element.WIND
|
||||
local power = 5
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ m:addOverride('xi.actions.weaponskills.brainshaker.onUseWeaponSkill', function(p
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
@ -106,7 +106,7 @@ m:addOverride('xi.actions.weaponskills.skullbreaker.onUseWeaponSkill', function(
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.INT_DOWN
|
||||
local actionElement = xi.element.FIRE
|
||||
local power = 10
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ m:addOverride('xi.actions.weaponskills.shadowstitch.onUseWeaponSkill', function(
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.BIND
|
||||
local actionElement = xi.element.ICE
|
||||
local power = 1
|
||||
|
|
@ -270,7 +270,7 @@ m:addOverride('xi.actions.weaponskills.mordant_rime.onUseWeaponSkill', function(
|
|||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.WEIGHT
|
||||
local actionElement = xi.element.WIND
|
||||
local power = 25
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m:addOverride('xi.actions.weaponskills.tachi_hobaku.onUseWeaponSkill', function(
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ m:addOverride('xi.actions.weaponskills.shockwave.onUseWeaponSkill', function(pla
|
|||
local power = 1
|
||||
local skillType = xi.skill.GREAT_SWORD
|
||||
local resist = xi.combat.magicHitRate.calculateResistRate(player, target, 0, skillType, 0, actionElement, 0, effectId, 0)
|
||||
local duration = math.floor((math.randomInt(0, 30) + tp * 0.01) * resist)
|
||||
local duration = math.floor((math.random(0, 30) + tp * 0.01) * resist)
|
||||
xi.weaponskills.handleWeaponskillEffect(player, target, effectId, actionElement, damage, power, duration)
|
||||
|
||||
return tpHits, extraHits, criticalHit, damage
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m:addOverride('xi.actions.weaponskills.shoulder_tackle.onUseWeaponSkill', functi
|
|||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
|
|||
|
|
@ -138,11 +138,9 @@ m:addOverride('xi.actions.weaponskills.coronach.onUseWeaponSkill', function(play
|
|||
params.overrideVE = 240
|
||||
params.rangedAccuracyBonus = 100
|
||||
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.MAIN, xi.aftermath.type.RELIC)
|
||||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doRangedWeaponskill(player, target, wsID, params, tp, action, primary)
|
||||
|
||||
-- Apply aftermath
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.RANGED, xi.aftermath.type.RELIC)
|
||||
|
||||
return tpHits, extraHits, criticalHit, damage
|
||||
end)
|
||||
|
||||
|
|
@ -158,8 +156,7 @@ m:addOverride('xi.actions.weaponskills.trueflight.onUseWeaponSkill', function(pl
|
|||
params.includemab = true
|
||||
params.dStat = xi.mod.AGI
|
||||
|
||||
-- Apply aftermath
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.RANGED, xi.aftermath.type.MYTHIC)
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.MAIN, xi.aftermath.type.MYTHIC)
|
||||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doMagicWeaponskill(player, target, wsID, params, tp, action, primary)
|
||||
return tpHits, extraHits, criticalHit, damage
|
||||
|
|
@ -177,8 +174,7 @@ m:addOverride('xi.actions.weaponskills.leaden_salute.onUseWeaponSkill', function
|
|||
params.includemab = true
|
||||
params.dStat = xi.mod.AGI
|
||||
|
||||
-- Apply aftermath
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.RANGED, xi.aftermath.type.MYTHIC)
|
||||
xi.aftermath.addStatusEffect(player, tp, xi.slot.MAIN, xi.aftermath.type.MYTHIC)
|
||||
|
||||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doMagicWeaponskill(player, target, wsID, params, tp, action, primary)
|
||||
return tpHits, extraHits, criticalHit, damage
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ m:addOverride('xi.actions.weaponskills.leg_sweep.onUseWeaponSkill', function(pla
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 33, 66, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 33, 66, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ m:addOverride('xi.actions.weaponskills.catastrophe.onUseWeaponSkill', function(p
|
|||
|
||||
-- Handle HP Drain
|
||||
if not target:isUndead() then
|
||||
local drain = math.floor(damage * math.randomInt(30, 70) / 100)
|
||||
local drain = math.floor(damage * math.random(30, 70) / 100)
|
||||
|
||||
drain = utils.clamp(drain, 0, targetHP)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ m:addOverride('xi.actions.weaponskills.starburst.onUseWeaponSkill', function(pla
|
|||
params.ele = xi.element.LIGHT
|
||||
params.dStat = xi.mod.INT
|
||||
|
||||
if math.randomInt(1, 100) <= 50 then
|
||||
if math.random(1, 100) <= 50 then
|
||||
params.ele = xi.element.DARK
|
||||
end
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ m:addOverride('xi.actions.weaponskills.sunburst.onUseWeaponSkill', function(play
|
|||
params.ele = xi.element.LIGHT
|
||||
params.dStat = xi.mod.INT
|
||||
|
||||
if math.randomInt(1, 100) <= 50 then
|
||||
if math.random(1, 100) <= 50 then
|
||||
params.ele = xi.element.DARK
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ m:addOverride('xi.actions.weaponskills.flat_blade.onUseWeaponSkill', function(pl
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.STUN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 1
|
||||
|
|
@ -166,8 +166,8 @@ m:addOverride('xi.actions.weaponskills.spirits_within.onUseWeaponSkill', functio
|
|||
|
||||
local damage = dmg
|
||||
damage = math.floor(damage * xi.combat.damage.calculateDamageAdjustment(target, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateAbsorption(target, xi.element.NONE, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateNullification(target, xi.element.NONE, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateAbsorption(target, xi.element.NONE, false))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateNullification(target, xi.element.NONE, false, true))
|
||||
damage = math.floor(target:handleSevereDamage(damage, false))
|
||||
|
||||
if damage > 0 then
|
||||
|
|
@ -298,19 +298,21 @@ m:addOverride('xi.actions.weaponskills.atonement.onUseWeaponSkill', function(pla
|
|||
return calcParams.tpHitsLanded, calcParams.extraHitsLanded, calcParams.criticalHit, damage
|
||||
end
|
||||
|
||||
-- Calculate damage based on target's CE and VE, clamped to the global damage cap.
|
||||
damage = utils.clamp(target:getCE(player) * cePercent + target:getVE(player) * vePercent, 0, globalDamageCap)
|
||||
-- Regular damage formula
|
||||
local dmg = target:getCE(player) * cePercent + target:getVE(player) * vePercent
|
||||
|
||||
-- This is here to account for damage adjustments needed because it is breath damage.
|
||||
damage = dmg
|
||||
damage = math.floor(damage * xi.combat.damage.calculateDamageAdjustment(target, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateAbsorption(target, xi.element.NONE, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateNullification(target, xi.element.NONE, false, false, false, true))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateAbsorption(target, xi.element.NONE, false))
|
||||
damage = math.floor(damage * xi.spells.damage.calculateNullification(target, xi.element.NONE, false, true))
|
||||
damage = math.floor(target:handleSevereDamage(damage, false))
|
||||
|
||||
if player:getMod(xi.mod.WEAPONSKILL_DAMAGE_BASE + wsID) > 0 then
|
||||
damage = damage * (100 + player:getMod(xi.mod.WEAPONSKILL_DAMAGE_BASE + wsID)) / 100
|
||||
end
|
||||
|
||||
damage = utils.clamp(damage, 0, globalDamageCap)
|
||||
calcParams.finalDmg = damage
|
||||
|
||||
-- If one or more hits land, Atonement always counts as landing both hits.
|
||||
|
|
@ -352,7 +354,7 @@ m:addOverride('xi.actions.weaponskills.death_blossom.onUseWeaponSkill', function
|
|||
local damage, criticalHit, tpHits, extraHits = xi.weaponskills.doPhysicalWeaponskill(player, target, wsID, params, tp, action, primary, taChar)
|
||||
|
||||
-- Handle status effect
|
||||
if math.randomInt(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
if math.random(1, 100) <= xi.weaponskills.fTP(tp, { 50, 75, 100 }) then
|
||||
local effectId = xi.effect.MAGIC_EVASION_DOWN
|
||||
local actionElement = xi.element.THUNDER
|
||||
local power = 10
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Pre-SoA Magic Burst Module
|
||||
-- Restores the pre-2015 magic burst multiplier: 1.25 + 0.05 per skillchain step.
|
||||
-- https://forum.square-enix.com/ffxi/threads/46531
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_magic_burst'
|
||||
|
||||
if xi.module.isContentEnabled('SOA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
m:addOverride('xi.spells.damage.calculateIfMagicBurst', function(caster, target, spellElement, magicBurstTier)
|
||||
if spellElement <= xi.element.NONE then
|
||||
return 1
|
||||
end
|
||||
|
||||
return 1.25 + 0.05 * utils.clamp(magicBurstTier, 1, 5)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Era Skillchain Module
|
||||
-- Adds a resistance check back to skillchain damage calculations.
|
||||
-- https://wiki.ffo.jp/html/32936.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_skillchain'
|
||||
|
||||
if xi.module.isContentEnabled('SOA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
local chainMultipliers =
|
||||
{
|
||||
[1] = { 0.50, 0.60, 0.70, 0.80, 0.90, 1.00 }, -- Level 1
|
||||
[2] = { 0.60, 0.75, 1.00, 1.25, 1.50, 1.75 }, -- Level 2
|
||||
[3] = { 1.00, 1.50, 1.75, 2.00, 2.25, 2.50 }, -- Level 3
|
||||
[4] = { 1.50, 1.80, 2.10, 2.40, 2.70, 3.00 }, -- Level 4 "Radiance/Umbra"
|
||||
}
|
||||
|
||||
local function getSkillchainElementToUse(target, skillchainType)
|
||||
-- Build skillchain available elements table.
|
||||
local elementTable = {}
|
||||
for i = xi.element.FIRE, xi.element.DARK do
|
||||
if xi.data.element.skillchainElementTable[i][skillchainType] > 0 then
|
||||
table.insert(elementTable, #elementTable + 1, i)
|
||||
end
|
||||
end
|
||||
|
||||
-- Early return: Single elemental SC. No need to continue.
|
||||
if #elementTable == 1 then
|
||||
return elementTable[1]
|
||||
end
|
||||
|
||||
-- Get lowest resistance rank value.
|
||||
local lowestResRank = 11
|
||||
local lowestElement = xi.element.FIRE
|
||||
|
||||
for j = #elementTable, 1, -1 do
|
||||
local resRankValue = target:getMod(xi.data.element.getElementalResistanceRankModifier(elementTable[j]))
|
||||
if resRankValue <= lowestResRank then
|
||||
lowestResRank = resRankValue
|
||||
lowestElement = elementTable[j]
|
||||
end
|
||||
end
|
||||
|
||||
return lowestElement
|
||||
end
|
||||
|
||||
m:addOverride('xi.combat.skillchain.calculateSkillchainDamage', function(actor, target, baseDamage)
|
||||
local skillchainEffect = target:getStatusEffect(xi.effect.SKILLCHAIN)
|
||||
if not skillchainEffect then
|
||||
return 0
|
||||
end
|
||||
|
||||
local skillchainType = skillchainEffect:getPower()
|
||||
if skillchainType == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local skillchainLevel = skillchainEffect:getTier()
|
||||
if skillchainLevel < 1 or skillchainLevel > 4 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local skillchainCount = skillchainEffect:getSubPower()
|
||||
if skillchainCount < 1 or skillchainCount > 6 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local skillchainElement = getSkillchainElementToUse(target, skillchainType)
|
||||
if not skillchainElement then
|
||||
return 0
|
||||
end
|
||||
|
||||
if xi.spells.damage.calculateNullification(target, skillchainElement, false, true, false, false) == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Calculate resist, base damage and multipliers.
|
||||
local finalDamage = math.abs(baseDamage) -- Damage from skillchain, no matter if absorbed or not.
|
||||
local levelMultiplier = chainMultipliers[skillchainLevel][skillchainCount]
|
||||
local bonusMultiplier = 1 + actor:getMod(xi.mod.SKILLCHAINBONUS) / 100
|
||||
local damageMultiplier = 1 + actor:getMod(xi.mod.SKILLCHAINDMG) / 10000
|
||||
local dayWeatherMultiplier = xi.spells.damage.calculateDayAndWeather(actor, skillchainElement, false)
|
||||
local staffMultiplier = xi.spells.damage.calculateElementalStaffBonus(actor, skillchainElement)
|
||||
local affinityMultiplier = xi.spells.damage.calculateElementalAffinityBonus(actor, skillchainElement)
|
||||
local resistRate = xi.combat.magicHitRate.calculateResistRate(actor, target, 0, 0, xi.skillRank.A_PLUS, skillchainElement, 0, 0, 0)
|
||||
local magicTakenMultiplier = xi.combat.damage.calculateDamageAdjustment(target, false, true, false, false)
|
||||
|
||||
-- Unconfirmed order.
|
||||
local inninMultiplier = 1 + actor:getMerit(xi.merit.INNIN_EFFECT) / 100
|
||||
local sengikoriMultiplier = 1 + target:getMod(xi.mod.SENGIKORI_SC_DMG_DEBUFF) / 100
|
||||
local absorptionMultiplier = xi.spells.damage.calculateAbsorption(target, skillchainElement, false, true, false, false)
|
||||
|
||||
-- Apply multipliers in order and floor after each step.
|
||||
finalDamage = math.floor(finalDamage * levelMultiplier)
|
||||
finalDamage = math.floor(finalDamage * bonusMultiplier) + actor:getMod(xi.mod.MAGIC_DAMAGE)
|
||||
finalDamage = math.floor(finalDamage * damageMultiplier)
|
||||
finalDamage = math.floor(finalDamage * dayWeatherMultiplier)
|
||||
finalDamage = math.floor(finalDamage * staffMultiplier)
|
||||
finalDamage = math.floor(finalDamage * affinityMultiplier)
|
||||
finalDamage = math.floor(finalDamage * resistRate)
|
||||
finalDamage = math.floor(finalDamage * magicTakenMultiplier)
|
||||
finalDamage = math.floor(finalDamage * inninMultiplier)
|
||||
finalDamage = math.floor(finalDamage * sengikoriMultiplier)
|
||||
finalDamage = math.floor(finalDamage * absorptionMultiplier)
|
||||
|
||||
-- Handle (reset) Sengikori.
|
||||
target:setMod(xi.mod.SENGIKORI_SC_DMG_DEBUFF, 0)
|
||||
|
||||
-- Handle other damage alterations.
|
||||
if finalDamage > 0 then
|
||||
finalDamage = utils.clamp(utils.handlePhalanx(target, finalDamage), 0, 99999)
|
||||
finalDamage = utils.clamp(utils.handleOneForAll(target, finalDamage), 0, 99999)
|
||||
finalDamage = utils.clamp(utils.handleStoneskin(target, finalDamage), 0, 99999)
|
||||
finalDamage = target:checkDamageCap(finalDamage)
|
||||
|
||||
target:takeDamage(finalDamage, actor, xi.attackType.SPECIAL, xi.damageType.ELEMENTAL + skillchainElement)
|
||||
|
||||
-- Handle absorbption.
|
||||
else
|
||||
target:addHP(-finalDamage)
|
||||
end
|
||||
|
||||
return finalDamage
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Era Signet Duration Module - Reduces duration of Signet effects by 3 hours.
|
||||
-- Changed May 10th, 2011 : https://wiki.ffo.jp/html/564.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_signet_duration'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
m:addOverride('xi.conquest.bestowSignet', function(player, pNation, pRank, mOffset)
|
||||
super(player, pNation, pRank, mOffset)
|
||||
|
||||
local signet = player:getStatusEffect(xi.effect.SIGNET)
|
||||
|
||||
if signet then
|
||||
signet:setDuration(signet:getDuration() - 3 * 3600 * 1000)
|
||||
end
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Module: Elemental Spirit Perpetuation Cost (level restriction)
|
||||
-- Reverts perpetuation cost which is recalculated on level restriction if a summoned elemental spirit is present.
|
||||
-- Source: https://forum.square-enix.com/ffxi/threads/22099-March-27-2012-%28JST%29-Version-Update
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_effect_level_restriction'
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
m:addOverride('xi.effects.level_restriction.onEffectGain', function(target, effect)
|
||||
super(target, effect)
|
||||
xi.job_utils.summoner.applySpiritPerpetuationCost(target)
|
||||
end)
|
||||
|
||||
m:addOverride('xi.effects.level_restriction.onEffectLose', function(target, effect)
|
||||
super(target, effect)
|
||||
xi.job_utils.summoner.applySpiritPerpetuationCost(target)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Automaton Utility Module
|
||||
-----------------------------------
|
||||
-- https://wiki.ffo.jp/html/19739.html
|
||||
-- https://wiki.ffo.jp/html/32936.html
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
require('scripts/globals/automaton')
|
||||
require('scripts/globals/pets/automaton')
|
||||
-----------------------------------
|
||||
local moduleName = 'automaton_global'
|
||||
|
||||
if not xi.module.isContentEnabled('WOTG') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
local maneuverList =
|
||||
{
|
||||
[xi.jobAbility.FIRE_MANEUVER ] = { effect = xi.effect.FIRE_MANEUVER, element = xi.element.FIRE, stat = xi.mod.STR },
|
||||
[xi.jobAbility.ICE_MANEUVER ] = { effect = xi.effect.ICE_MANEUVER, element = xi.element.ICE, stat = xi.mod.INT },
|
||||
[xi.jobAbility.WIND_MANEUVER ] = { effect = xi.effect.WIND_MANEUVER, element = xi.element.WIND, stat = xi.mod.AGI },
|
||||
[xi.jobAbility.EARTH_MANEUVER ] = { effect = xi.effect.EARTH_MANEUVER, element = xi.element.EARTH, stat = xi.mod.VIT },
|
||||
[xi.jobAbility.THUNDER_MANEUVER] = { effect = xi.effect.THUNDER_MANEUVER, element = xi.element.THUNDER, stat = xi.mod.DEX },
|
||||
[xi.jobAbility.WATER_MANEUVER ] = { effect = xi.effect.WATER_MANEUVER, element = xi.element.WATER, stat = xi.mod.MND },
|
||||
[xi.jobAbility.LIGHT_MANEUVER ] = { effect = xi.effect.LIGHT_MANEUVER, element = xi.element.LIGHT, stat = xi.mod.CHR },
|
||||
[xi.jobAbility.DARK_MANEUVER ] = { effect = xi.effect.DARK_MANEUVER, element = xi.element.DARK, stat = nil },
|
||||
}
|
||||
|
||||
local function getAddBurdenValue(player, maneuverElement, maneuverStat)
|
||||
-- Dark Maneuvers
|
||||
if maneuverElement == xi.element.DARK then
|
||||
local frameEquipped = player:getAutomatonFrame()
|
||||
|
||||
if
|
||||
frameEquipped == xi.automaton.frame.VALOREDGE or
|
||||
frameEquipped == xi.automaton.frame.SHARPSHOT
|
||||
then
|
||||
return 8
|
||||
end
|
||||
|
||||
return 14
|
||||
else
|
||||
-- Fire, Ice, Wind, Earth, Lightning, Water, Light Maneuvers
|
||||
local statDifference = player:getStat(maneuverStat) - player:getPet():getStat(maneuverStat)
|
||||
|
||||
if statDifference >= 4 then
|
||||
return 14
|
||||
elseif statDifference >= 0 then
|
||||
return 19 - statDifference
|
||||
else
|
||||
return 20
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove Overdrive returning 3 maneuvers while active.
|
||||
m:addOverride('xi.automaton.getManeuverCount', function(master, maneuvers)
|
||||
if not master then
|
||||
return 0
|
||||
end
|
||||
|
||||
return math.min(maneuvers, 3)
|
||||
end)
|
||||
|
||||
-- Remove level scaling maneuver stat bonus.
|
||||
m:addOverride('xi.automaton.onUseManeuver', function(player, target, ability, action)
|
||||
local pet = player:getPet()
|
||||
|
||||
if not pet then
|
||||
return
|
||||
end
|
||||
|
||||
local maneuverInfo = maneuverList[ability:getID()]
|
||||
local element = maneuverInfo.element - 1
|
||||
local burdenValue = getAddBurdenValue(player, maneuverInfo.element, maneuverInfo.stat)
|
||||
local overload = target:addBurden(element, burdenValue)
|
||||
|
||||
if
|
||||
overload ~= 0 and
|
||||
(player:getMod(xi.mod.PREVENT_OVERLOAD) > 0 or pet:getMod(xi.mod.PREVENT_OVERLOAD) > 0) and
|
||||
player:delStatusEffectSilent(xi.effect.WATER_MANEUVER)
|
||||
then
|
||||
overload = 0
|
||||
end
|
||||
|
||||
action:messageID(player:getID(), xi.msg.basic.AUTO_OVERLOAD_CHANCE)
|
||||
|
||||
if overload ~= 0 then
|
||||
target:removeAllManeuvers()
|
||||
target:addStatusEffect(xi.effect.OVERLOAD, { duration = overload, origin = player })
|
||||
pet:addStatusEffect(xi.effect.OVERLOAD, { duration = overload, origin = pet })
|
||||
action:messageID(player:getID(), xi.msg.basic.AUTO_OVERLOADED)
|
||||
else
|
||||
if target:getActiveManeuverCount() == 3 then
|
||||
target:removeOldestManeuver()
|
||||
end
|
||||
|
||||
local maneuverBonus = 1 + target:getMod(xi.mod.MANEUVER_BONUS)
|
||||
|
||||
target:addStatusEffect(maneuverInfo.effect, { power = maneuverBonus, duration = utils.clamp(pet:getLocalVar('MANEUVER_DURATION'), 60, 300), origin = player })
|
||||
end
|
||||
|
||||
return target:getOverloadChance(element)
|
||||
end)
|
||||
|
||||
return m
|
||||
|
|
@ -209,7 +209,7 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
local snakeEye = caster:getStatusEffect(xi.effect.SNAKE_EYE)
|
||||
|
||||
if snakeEye then
|
||||
if roll >= 5 and math.randomInt(1, 100) < snakeEye:getPower() then
|
||||
if roll >= 5 and math.random(1, 100) < snakeEye:getPower() then
|
||||
roll = 11
|
||||
else
|
||||
roll = roll + 1
|
||||
|
|
@ -217,7 +217,7 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
|
||||
caster:delStatusEffect(xi.effect.SNAKE_EYE)
|
||||
else
|
||||
roll = roll + math.randomInt(1, 6)
|
||||
roll = roll + math.random(1, 6)
|
||||
end
|
||||
|
||||
if roll >= 12 then -- bust
|
||||
|
|
@ -251,9 +251,8 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
|
||||
-- Snake Eye: Revert to cooldown reduction from merit points, remove bonus free XI effect.
|
||||
-- Source: https://www.bg-wiki.com/ffxi/Version_Update_(05/15/2012)
|
||||
-- Merit value is set to 150s/level by modules/abyssea/sql/job_adjustments.sql
|
||||
m:addOverride('xi.job_utils.corsair.useSnakeEye', function(player, action)
|
||||
local recastReduction = player:getMerit(xi.merit.SNAKE_EYE) - 150
|
||||
local recastReduction = (player:getMerit(xi.merit.SNAKE_EYE) / 10) * 60
|
||||
action:setRecast(action:getRecast() - recastReduction)
|
||||
|
||||
player:addStatusEffect(xi.effect.SNAKE_EYE, { power = 0, duration = 60, origin = player })
|
||||
|
|
@ -295,8 +294,7 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
player:delStatusEffect(selected:getEffectType())
|
||||
player:delStatusEffectSilent(xi.effect.DOUBLE_UP_CHANCE)
|
||||
|
||||
-- Merit value is set to 150s/level by modules/abyssea/sql/job_adjustments.sql
|
||||
local recastReduction = player:getMerit(xi.merit.FOLD) - 150
|
||||
local recastReduction = (player:getMerit(xi.merit.FOLD) / 10) * 60
|
||||
action:setRecast(action:getRecast() - recastReduction)
|
||||
end
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ if not xi.module.isContentEnabled('ROV') then
|
|||
local drainamount = 0
|
||||
|
||||
if wyvern:getHP() ~= wyvern:getMaxHP() then
|
||||
drainamount = (math.randomInt(25, 35) / 100) * playerHP
|
||||
drainamount = (math.random(25, 35) / 100) * playerHP
|
||||
drainamount = drainamount * (1 - (0.01 * player:getJobPointLevel(xi.jp.SPIRIT_LINK_EFFECT)))
|
||||
end
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
local drainAmount = 0
|
||||
|
||||
if wyvern:getHP() ~= wyvern:getMaxHP() then
|
||||
drainAmount = (math.randomInt(25, 35) / 100) * playerHP
|
||||
drainAmount = (math.random(25, 35) / 100) * playerHP
|
||||
drainAmount = drainAmount * (1 - (0.01 * player:getJobPointLevel(xi.jp.SPIRIT_LINK_EFFECT)))
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ if not xi.module.isContentEnabled('SOA') then
|
|||
-- Source: https://forum.square-enix.com/ffxi/threads/44592-Oct-7-2014-%28JST%29-Version-Update
|
||||
m:addOverride('xi.job_utils.ninja.useSange', function(player, target, ability, action)
|
||||
local meritReduction = player:getMerit(xi.merit.SANGE) - 150
|
||||
action:setRecast(math.max(0, action:getRecast() - meritReduction))
|
||||
ability:setRecast(math.max(0, ability:getRecast() - meritReduction))
|
||||
|
||||
-- Apply Sange effect (shadows are consumed when the ranged attack fires)
|
||||
player:addStatusEffect(xi.effect.SANGE, { duration = 60, origin = player })
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ if not xi.module.isContentEnabled('ROV') then
|
|||
local defense = player:getMainLvl() == 75 and 23 or 21
|
||||
|
||||
-- Apply STONESKIN effect but display as RAMPART icon
|
||||
-- TODO: subType 2 not yet implemented for magical only stoneskin
|
||||
target:addStatusEffect(xi.effect.STONESKIN, { power = defense, duration = duration, origin = player, icon = xi.effect.RAMPART, subType = 2, subPower = stoneskinHP })
|
||||
|
||||
return xi.effect.RAMPART
|
||||
|
|
@ -23,7 +24,10 @@ if not xi.module.isContentEnabled('ROV') then
|
|||
-- Stoneskin onEffectGain: Add defense buff when displayed as RAMPART
|
||||
m:addOverride('xi.effects.stoneskin.onEffectGain', function(target, effect)
|
||||
if effect:getIcon() == xi.effect.RAMPART then
|
||||
effect:addMod(xi.mod.STONESKIN, effect:getSubPower())
|
||||
effect:addMod(xi.mod.DEF, effect:getPower())
|
||||
else
|
||||
effect:addMod(xi.mod.STONESKIN, effect:getPower())
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
@ -67,8 +71,7 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
local recastReduction = player:getMerit(xi.merit.FEALTY) - 150
|
||||
action:setRecast(action:getRecast() - recastReduction)
|
||||
|
||||
-- Divide by merit value (150s in pre-Abyssea) to recover merit rank count for gear scaling
|
||||
local enhFealty = (player:getMerit(xi.merit.FEALTY) / 150) * player:getMod(xi.mod.ENHANCES_FEALTY)
|
||||
local enhFealty = (player:getMerit(xi.merit.FEALTY) / 5) * player:getMod(xi.mod.ENHANCES_FEALTY)
|
||||
local duration = 60 + enhFealty
|
||||
|
||||
player:addStatusEffect(xi.effect.FEALTY, { power = 1, duration = duration, origin = player })
|
||||
|
|
@ -97,12 +100,12 @@ if not xi.module.isContentEnabled('ABYSSEA') then
|
|||
then
|
||||
local resistanceRate = xi.combat.magicHitRate.calculateResistRate(player, target, 0, 0, xi.skillRank.A_PLUS, xi.element.THUNDER, xi.mod.INT, xi.effect.STUN, 0)
|
||||
if xi.data.statusEffect.isResistRateSuccessfull(xi.effect.STUN, resistanceRate, 0) then
|
||||
target:addStatusEffect(xi.effect.STUN, { power = 1, duration = math.randomInt(2, 8) * resistanceRate, origin = player })
|
||||
target:addStatusEffect(xi.effect.STUN, { power = 1, duration = math.random(2, 8) * resistanceRate, origin = player })
|
||||
end
|
||||
end
|
||||
|
||||
-- Randomize damage
|
||||
local randomizer = 1 + (math.randomInt(1, 5) / 100)
|
||||
local randomizer = 1 + (math.random(1, 5) / 100)
|
||||
|
||||
damage = damage * randomizer
|
||||
damage = utils.handleStoneskin(target, damage)
|
||||
|
|
|
|||
|
|
@ -1,142 +0,0 @@
|
|||
-----------------------------------
|
||||
-- Module: Puppetmaster Job Adjustments
|
||||
-----------------------------------
|
||||
require('modules/module_utils')
|
||||
-----------------------------------
|
||||
local moduleName = 'era_job_utils_puppetmaster'
|
||||
|
||||
local m = Module:new(moduleName)
|
||||
|
||||
if xi.module.isContentEnabled('ABYSSEA') then
|
||||
return { name = moduleName }
|
||||
end
|
||||
|
||||
-- Overdrive: Revert duration from 180 to 60 seconds : https://wiki.ffo.jp/html/954.html
|
||||
m:addOverride('xi.job_utils.puppetmaster.onAbilityUseOverdrive', function(player, target, ability, action)
|
||||
local pet = player:getPet()
|
||||
|
||||
player:addStatusEffect(xi.effect.OVERDRIVE, { duration = 60 + player:getMod(xi.mod.OVERDRIVE_BONUS_DURATION), origin = player })
|
||||
|
||||
if pet then
|
||||
pet:addStatusEffect(xi.effect.OVERDRIVE, { duration = 60 + player:getMod(xi.mod.OVERDRIVE_BONUS_DURATION), origin = pet })
|
||||
action:ID(player:getID(), pet:getID())
|
||||
end
|
||||
|
||||
return xi.effect.OVERDRIVE
|
||||
end)
|
||||
|
||||
-- Repair: Revert recast to a flat 180 seconds : https://wiki.ffo.jp/html/954.html
|
||||
m:addOverride('xi.job_utils.puppetmaster.onAbilityCheckRepair', function(player, target, ability)
|
||||
local msg, param = super(player, target, ability)
|
||||
|
||||
if msg == 0 then
|
||||
ability:setRecast(180)
|
||||
end
|
||||
|
||||
return msg, param
|
||||
end)
|
||||
|
||||
local removableEffects =
|
||||
{
|
||||
-- Songs
|
||||
xi.effect.ELEGY,
|
||||
xi.effect.REQUIEM,
|
||||
xi.effect.THRENODY,
|
||||
|
||||
-- Enfeebling
|
||||
xi.effect.BLINDNESS,
|
||||
xi.effect.PARALYSIS,
|
||||
xi.effect.SILENCE,
|
||||
xi.effect.CURSE_I,
|
||||
xi.effect.CURSE_II,
|
||||
xi.effect.DISEASE,
|
||||
xi.effect.PLAGUE,
|
||||
xi.effect.WEIGHT,
|
||||
xi.effect.BIND,
|
||||
xi.effect.ADDLE,
|
||||
xi.effect.SLOW,
|
||||
xi.effect.PETRIFICATION,
|
||||
|
||||
-- DoTs
|
||||
xi.effect.BIO,
|
||||
xi.effect.DIA,
|
||||
xi.effect.POISON,
|
||||
xi.effect.BURN,
|
||||
xi.effect.FROST,
|
||||
xi.effect.CHOKE,
|
||||
xi.effect.RASP,
|
||||
xi.effect.SHOCK,
|
||||
xi.effect.DROWN,
|
||||
|
||||
-- Main Stat Downs
|
||||
xi.effect.STR_DOWN,
|
||||
xi.effect.DEX_DOWN,
|
||||
xi.effect.VIT_DOWN,
|
||||
xi.effect.AGI_DOWN,
|
||||
xi.effect.INT_DOWN,
|
||||
xi.effect.MND_DOWN,
|
||||
xi.effect.CHR_DOWN,
|
||||
|
||||
-- Combat Stat Downs
|
||||
xi.effect.ACCURACY_DOWN,
|
||||
xi.effect.ATTACK_DOWN,
|
||||
xi.effect.EVASION_DOWN,
|
||||
xi.effect.DEFENSE_DOWN,
|
||||
|
||||
-- Magic Stat Downs
|
||||
xi.effect.MAGIC_ACC_DOWN,
|
||||
xi.effect.MAGIC_ATK_DOWN,
|
||||
xi.effect.MAGIC_EVASION_DOWN,
|
||||
xi.effect.MAGIC_DEF_DOWN,
|
||||
|
||||
-- HP/MP/TP Stat Downs
|
||||
xi.effect.MAX_TP_DOWN,
|
||||
xi.effect.MAX_MP_DOWN,
|
||||
xi.effect.MAX_HP_DOWN
|
||||
}
|
||||
|
||||
local function removeStatusEffects(pet, amountToRemove)
|
||||
local effectsRemoved = 0
|
||||
|
||||
for _, effectId in ipairs(removableEffects) do
|
||||
if effectsRemoved >= amountToRemove then
|
||||
break
|
||||
end
|
||||
|
||||
if pet:delStatusEffect(effectId) then
|
||||
effectsRemoved = effectsRemoved + 1
|
||||
end
|
||||
end
|
||||
|
||||
return effectsRemoved
|
||||
end
|
||||
|
||||
-- Repair: Remove the initial burst heal, leaving only the Regen and status removal effects
|
||||
m:addOverride('xi.job_utils.puppetmaster.onAbilityUseRepair', function(player, target, ability, action)
|
||||
local pet = player:getPet()
|
||||
if not pet then
|
||||
return
|
||||
end
|
||||
|
||||
-- Self-cast ability but reports on pet
|
||||
action:ID(player:getID(), pet:getID())
|
||||
|
||||
local oilEquipped = xi.job_utils.puppetmaster.oilData[player:getEquipID(xi.slot.AMMO)]
|
||||
local regenAmount = oilEquipped.regen
|
||||
local regenTime = oilEquipped.duration
|
||||
|
||||
removeStatusEffects(pet, player:getMod(xi.mod.REPAIR_EFFECT))
|
||||
|
||||
local bonus = 1 + player:getMerit(xi.merit.REPAIR_EFFECT) / 100 + player:getMod(xi.mod.REPAIR_POTENCY) / 100
|
||||
regenAmount = regenAmount * bonus
|
||||
|
||||
pet:wakeUp()
|
||||
|
||||
pet:delStatusEffect(xi.effect.REGEN)
|
||||
pet:addStatusEffect(xi.effect.REGEN, { power = regenAmount, duration = regenTime, origin = player, tick = 3 }) -- 3 = tick, each 3 seconds.
|
||||
player:removeAmmo(1)
|
||||
|
||||
ability:setMsg(xi.msg.basic.USES_JA)
|
||||
end)
|
||||
|
||||
return m
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue