mirror of
https://github.com/0O0o0oOoO00/Alas.git
synced 2026-05-14 23:59:26 +08:00
2157 lines
73 KiB
C++
2157 lines
73 KiB
C++
#include "cracker.hpp"
|
|
|
|
#include <lua/lua.hpp>
|
|
#include <spdlog/spdlog.h>
|
|
#include <sol/as_args.hpp>
|
|
#include <sol/sol.hpp>
|
|
|
|
#include "ui/ui.hpp"
|
|
#include "ui/hook.hpp"
|
|
#include "utils.hpp"
|
|
#include "il2cpp.hpp"
|
|
#include "skincache.hpp"
|
|
|
|
using fnset_TimeScaleT = void(*)(float);
|
|
|
|
static fnset_TimeScaleT get_Time_set_timeScale() {
|
|
static fnset_TimeScaleT fn = []() {
|
|
Il2CppDomain* domain = il2cpp_domain_get();
|
|
size_t assembly_count = 0;
|
|
Il2CppAssembly** assemblies = il2cpp_domain_get_assemblies(domain, &assembly_count);
|
|
|
|
Il2CppClass* cls = nullptr;
|
|
for (size_t i = 0; i < assembly_count; ++i) {
|
|
Il2CppImage* image = il2cpp_assembly_get_image(assemblies[i]);
|
|
Il2CppClass* klass = il2cpp_class_from_name(image, "UnityEngine", "Time");
|
|
if (klass != nullptr) {
|
|
cls = klass;
|
|
break;
|
|
}
|
|
}
|
|
if (cls != nullptr) {
|
|
MethodInfo* method_info = il2cpp_class_get_method_from_name(cls, "set_timeScale", 1);
|
|
if (method_info != nullptr) {
|
|
auto method = reinterpret_cast<fnset_TimeScaleT>(method_info->methodPointer);
|
|
SPDLOG_INFO("Found Time.set_timeScale at {}", (void*)method_info->methodPointer);
|
|
return method;
|
|
}
|
|
}
|
|
SPDLOG_ERROR("Failed to get Time.set_timeScale");
|
|
throw std::runtime_error("Failed to get Time.set_timeScale");
|
|
}();
|
|
return fn;
|
|
}
|
|
|
|
#define IS_ENABLED(f) m_flag.f.load()
|
|
|
|
#define ENABLE(n) \
|
|
SPDLOG_INFO("Enable {}", #n); \
|
|
m_flag.n.store(true)
|
|
|
|
#define DISABLE(n) \
|
|
SPDLOG_INFO("Disable {}", #n); \
|
|
m_flag.n.store(false)
|
|
|
|
#define CALLED(f) \
|
|
if (IS_ENABLED(HOOKED_LUA_FUNCTION_TRACE)) { \
|
|
SPDLOG_INFO("{} called", #f); \
|
|
}
|
|
|
|
LuaStatePauser::LuaStatePauser(lua_State* L) : m_L(L) {}
|
|
|
|
void LuaStatePauser::do_when_paused(const std::function<void()>& func) {
|
|
auto _ = std::lock_guard<std::mutex>(m_atomic_pause);
|
|
ensure_debug_hook();
|
|
auto lk = std::binary_semaphore(0);
|
|
|
|
g_pause_flag.store(&lk);
|
|
g_lua_state_operation.store(&func);
|
|
lk.acquire();
|
|
SPDLOG_INFO("lua operation finished");
|
|
}
|
|
|
|
void LuaStatePauser::ensure_debug_hook() {
|
|
if (lua_gethook(m_L) != LuaStatePauser::debug_hook) {
|
|
register_debug_hook();
|
|
}
|
|
}
|
|
|
|
std::atomic<std::binary_semaphore*> LuaStatePauser::g_pause_flag = nullptr;
|
|
|
|
std::atomic<const std::function<void()>*> LuaStatePauser::g_lua_state_operation = nullptr;
|
|
|
|
void LuaStatePauser::register_debug_hook() {
|
|
SPDLOG_INFO("registering debug hook");
|
|
int ret = lua_sethook(m_L, LuaStatePauser::debug_hook, LUA_MASKCALL | LUA_MASKRET, 0);
|
|
if (ret != 1) {
|
|
SPDLOG_INFO("set pause hook failed with code: {}", ret);
|
|
}
|
|
}
|
|
|
|
extern bool g_is_game_loaded;
|
|
|
|
void LuaStatePauser::debug_hook(lua_State *L, lua_Debug *ar) {
|
|
if (g_is_game_loaded) {
|
|
auto callback = g_lua_state_operation.load();
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
SPDLOG_INFO("pause triggered, operate lua state");
|
|
(*callback)();
|
|
auto f = g_pause_flag.load();
|
|
g_lua_state_operation.store(nullptr);
|
|
g_pause_flag.store(nullptr);
|
|
f->release();
|
|
}
|
|
}
|
|
|
|
Cracker::Cracker(bool need_pause)
|
|
: m_state([]() -> lua_State* {
|
|
auto new_tr = lua_newthread(Utils::get_lua_state());
|
|
SPDLOG_INFO("new lua_State: {}", (void*)new_tr);
|
|
return new_tr;
|
|
}())
|
|
, m_lua_state_pauser(Utils::get_lua_state()) {
|
|
try {
|
|
if (need_pause) {
|
|
load_cracker_with_pause();
|
|
} else {
|
|
load_cracker_without_pause();
|
|
}
|
|
} catch(std::exception& e) {
|
|
SPDLOG_ERROR("Cracker load error: {}", e.what());
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_CRACKER_UI
|
|
std::mutex g_cracker_lock;
|
|
Cracker& Cracker::Instance() {
|
|
std::lock_guard guard(g_cracker_lock);
|
|
static auto* instance = new Cracker;
|
|
return *instance;
|
|
}
|
|
#else
|
|
Cracker& Cracker::Instance(bool need_pause) {
|
|
static auto* instance = new Cracker(need_pause);
|
|
return *instance;
|
|
}
|
|
#endif
|
|
|
|
int Cracker::get_coin() {
|
|
ensure_data_proxies();
|
|
double coin = m_data_proxy.player["data"]["gold"];
|
|
return static_cast<int>(coin);
|
|
}
|
|
|
|
int Cracker::get_oil() {
|
|
ensure_data_proxies();
|
|
double oil = m_data_proxy.player["data"]["oil"];
|
|
return static_cast<int>(oil);
|
|
}
|
|
|
|
int Cracker::get_gems() {
|
|
ensure_data_proxies();
|
|
double gems = m_data_proxy.player["data"]["awardGem"];
|
|
return static_cast<int>(gems);
|
|
}
|
|
|
|
int Cracker::get_level() {
|
|
ensure_data_proxies();
|
|
double level = m_data_proxy.player["data"]["level"];
|
|
return static_cast<int>(level);
|
|
}
|
|
|
|
int Cracker::get_exp() {
|
|
ensure_data_proxies();
|
|
double exp = m_data_proxy.player["data"]["exp"];
|
|
return static_cast<int>(exp);
|
|
}
|
|
|
|
int Cracker::get_merit() {
|
|
ensure_data_proxies();
|
|
double merit = m_data_proxy.player["data"]["exploit"];
|
|
return static_cast<int>(merit);
|
|
}
|
|
|
|
int Cracker::get_guild_coin() {
|
|
ensure_data_proxies();
|
|
double guild_coin = m_data_proxy.player["data"]["guildCoin"];
|
|
return static_cast<int>(guild_coin);
|
|
}
|
|
|
|
int Cracker::get_design_prt() {
|
|
ensure_data_proxies();
|
|
double design_prt = m_data_proxy.player["data"]["design_prt"];
|
|
return static_cast<int>(design_prt);
|
|
}
|
|
|
|
#define CORE_DATA_ITEM_ID 59900
|
|
|
|
int Cracker::get_core_data() {
|
|
ensure_data_proxies();
|
|
Lua::Table storage = m_data_proxy.storage["data"];
|
|
double core_data = storage.get<Lua::Table>(CORE_DATA_ITEM_ID)["count"];
|
|
return static_cast<int>(core_data);
|
|
}
|
|
|
|
#define MEDAL_ITEM_ID 15001
|
|
|
|
int Cracker::get_medal() {
|
|
ensure_data_proxies();
|
|
Lua::Table storage = m_data_proxy.storage["data"];
|
|
double medal = storage.get<Lua::Table>(MEDAL_ITEM_ID)["count"];
|
|
return static_cast<int>(medal);
|
|
}
|
|
|
|
int Cracker::get_pt() {
|
|
ensure_data_proxies();
|
|
double pt = m_data_proxy.player["data"]["pt"];
|
|
return static_cast<int>(pt);
|
|
}
|
|
|
|
#define SPECIALIZED_CORE_ITEM_ID 59010
|
|
|
|
int Cracker::get_specialized_core() {
|
|
ensure_data_proxies();
|
|
Lua::Table storage = m_data_proxy.storage["data"];
|
|
double specialized_core = storage.get<Lua::Table>(SPECIALIZED_CORE_ITEM_ID)["count"];
|
|
return static_cast<int>(specialized_core);
|
|
}
|
|
|
|
int Cracker::get_curr_action_point() {
|
|
ensure_data_proxies();
|
|
double curr_action_point = m_data_proxy.world["world"]["fields"]["staminaMgr"]["fields"]["stamina"];
|
|
return static_cast<int>(curr_action_point);
|
|
}
|
|
|
|
std::map<Cracker::ShipId, Cracker::ShipInfo> Cracker::scan_dock() {
|
|
ensure_data_proxies();
|
|
std::map<ShipId, ShipInfo> ships;
|
|
Lua::Table dock = m_data_proxy.dock["data"];
|
|
for (auto& [ship_id, ship_info] : dock) {
|
|
Lua::Table ship_data = ship_info.as<Lua::Table>();
|
|
double id = ship_data["id"];
|
|
ships[static_cast<ShipId>(id)] = {
|
|
.config_id = static_cast<int>(ship_data.get<double>("configId")),
|
|
.emotion = static_cast<int>(ship_data.get<double>("energy")),
|
|
.rarity = static_cast<int>(ship_data.get<double>("star")),
|
|
.level = static_cast<int>(ship_data.get<double>("level")),
|
|
.exp = static_cast<int>(ship_data.get<double>("exp")),
|
|
.curr_star = static_cast<int>(ship_data.get<double>("state")),
|
|
};
|
|
}
|
|
return ships;
|
|
}
|
|
|
|
std::map<Cracker::StorageItemId, Cracker::StorageItemCount> Cracker::scan_storage() {
|
|
ensure_data_proxies();
|
|
std::map<StorageItemId, StorageItemCount> items;
|
|
Lua::Table storage = m_data_proxy.storage["data"];
|
|
for (auto& [item_id, item_info] : storage) {
|
|
Lua::Table item_data = item_info.as<Lua::Table>();
|
|
double config_id = item_data["configId"];
|
|
double count = item_data["count"];
|
|
items[static_cast<StorageItemId>(config_id)] = static_cast<StorageItemCount>(count);
|
|
}
|
|
return items;
|
|
}
|
|
|
|
std::optional<Cracker::ShipInfo> Cracker::get_ship_info(ShipId ship_id) {
|
|
ensure_data_proxies();
|
|
double id = static_cast<double>(ship_id);
|
|
Lua::Table dock = m_data_proxy.dock["data"];
|
|
try {
|
|
Lua::Table ship_data = dock.get<Lua::Table>(id);
|
|
return ShipInfo{
|
|
.config_id = static_cast<int>(ship_data.get<double>("configId")),
|
|
.emotion = static_cast<int>(ship_data.get<double>("energy")),
|
|
.rarity = static_cast<int>(ship_data.get<double>("star")),
|
|
.level = static_cast<int>(ship_data.get<double>("level")),
|
|
.exp = static_cast<int>(ship_data.get<double>("exp")),
|
|
.curr_star = static_cast<int>(ship_data.get<double>("state")),
|
|
};
|
|
}
|
|
catch (const std::exception& e) {
|
|
return std::nullopt;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<Cracker::StorageItemCount> Cracker::get_storage_item_count(StorageItemId item_id) {
|
|
ensure_data_proxies();
|
|
double id = static_cast<double>(item_id);
|
|
Lua::Table storage = m_data_proxy.storage["data"];
|
|
try {
|
|
Lua::Table item_data = storage.get<Lua::Table>(id);
|
|
return static_cast<StorageItemCount>(item_data.get<double>("count"));
|
|
}
|
|
catch (const std::exception& e) {
|
|
return std::nullopt;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
void Cracker::disable_all() {
|
|
disable_hooked_lua_function_trace();
|
|
disable_global_ship_properties_crack();
|
|
disable_fast_stage_move();
|
|
disable_remove_hard_mode_ship_properties_limit();
|
|
disable_remove_hard_mode_ship_type_limit();
|
|
disable_fake_player();
|
|
disable_no_bb_animation();
|
|
disable_no_emotion_warning();
|
|
disable_opsi_fast_move();
|
|
disable_gg_factor();
|
|
disable_global_speedup();
|
|
disable_exercise_god_mode();
|
|
disable_exercise_more_power();
|
|
disable_fast_wave();
|
|
disable_monster_kill_self();
|
|
disable_skip_battle_celebrate();
|
|
disable_better_global_speedup();
|
|
disable_no_damage();
|
|
disable_opsi_force_auto();
|
|
disable_opsi_no_map_fog();
|
|
disable_skip_ship_gain_show();
|
|
disable_chapter_force_enable_auto_fight();
|
|
disable_chapter_skip_precombat();
|
|
disable_chapter_auto_next_battle();
|
|
disable_chapter_auto_ambush();
|
|
disable_chapter_auto_clear();
|
|
disable_skip_story();
|
|
disable_infinite_battle();
|
|
}
|
|
|
|
void Cracker::enable_infinite_battle() {
|
|
ENABLE(INFINITE_BATTLE);
|
|
}
|
|
|
|
void Cracker::disable_infinite_battle() {
|
|
DISABLE(INFINITE_BATTLE);
|
|
}
|
|
|
|
void Cracker::enable_hooked_lua_function_trace() {
|
|
ENABLE(HOOKED_LUA_FUNCTION_TRACE);
|
|
}
|
|
|
|
void Cracker::disable_hooked_lua_function_trace() {
|
|
DISABLE(HOOKED_LUA_FUNCTION_TRACE);
|
|
}
|
|
|
|
void Cracker::enable_skip_story() {
|
|
ENABLE(SKIP_STORY);
|
|
}
|
|
|
|
void Cracker::disable_skip_story() {
|
|
DISABLE(SKIP_STORY);
|
|
}
|
|
|
|
void Cracker::enable_chapter_auto_clear() {
|
|
ENABLE(CHAPTER_AUTO_CLEAR);
|
|
}
|
|
|
|
void Cracker::disable_chapter_auto_clear() {
|
|
DISABLE(CHAPTER_AUTO_CLEAR);
|
|
}
|
|
|
|
void Cracker::enable_chapter_skip_precombat() {
|
|
ENABLE(CHAPTER_SKIP_PRECOMBAT);
|
|
}
|
|
|
|
void Cracker::disable_chapter_skip_precombat() {
|
|
DISABLE(CHAPTER_SKIP_PRECOMBAT);
|
|
}
|
|
|
|
void Cracker::enable_chapter_auto_next_battle() {
|
|
ENABLE(CHAPTER_AUTO_NEXT_BATTLE);
|
|
}
|
|
|
|
void Cracker::disable_chapter_auto_next_battle() {
|
|
DISABLE(CHAPTER_AUTO_NEXT_BATTLE);
|
|
}
|
|
|
|
void Cracker::enable_chapter_force_enable_auto_fight() {
|
|
ENABLE(CHAPTER_FORCE_ENABLE_AUTO_FIGHT);
|
|
}
|
|
|
|
void Cracker::disable_chapter_force_enable_auto_fight() {
|
|
DISABLE(CHAPTER_FORCE_ENABLE_AUTO_FIGHT);
|
|
}
|
|
|
|
void Cracker::enable_chapter_auto_ambush() {
|
|
ENABLE(CHAPTER_AUTO_AMBUSH);
|
|
}
|
|
|
|
void Cracker::disable_chapter_auto_ambush() {
|
|
DISABLE(CHAPTER_AUTO_AMBUSH);
|
|
}
|
|
|
|
void Cracker::enable_skip_ship_gain_show() {
|
|
ENABLE(SKIP_SHIP_GAIN_SHOW);
|
|
}
|
|
|
|
void Cracker::disable_skip_ship_gain_show() {
|
|
DISABLE(SKIP_SHIP_GAIN_SHOW);
|
|
}
|
|
|
|
void Cracker::enable_opsi_force_auto() {
|
|
ENABLE(OPSI_FORCE_AUTO);
|
|
}
|
|
|
|
void Cracker::disable_opsi_force_auto() {
|
|
DISABLE(OPSI_FORCE_AUTO);
|
|
}
|
|
|
|
void Cracker::enable_opsi_no_map_fog() {
|
|
ENABLE(OPSI_NO_MAP_FOG);
|
|
}
|
|
|
|
void Cracker::disable_opsi_no_map_fog() {
|
|
DISABLE(OPSI_NO_MAP_FOG);
|
|
}
|
|
|
|
void Cracker::enable_all_skin() {
|
|
ENABLE(ALL_SKIN);
|
|
}
|
|
|
|
void Cracker::disable_all_skin() {
|
|
DISABLE(ALL_SKIN);
|
|
}
|
|
|
|
void Cracker::enable_no_damage() {
|
|
ENABLE(NO_DAMAGE);
|
|
}
|
|
|
|
void Cracker::disable_no_damage() {
|
|
DISABLE(NO_DAMAGE);
|
|
}
|
|
|
|
void Cracker::enable_better_global_speedup() {
|
|
ENABLE(BETTER_GLOBAL_SPEEDUP);
|
|
better_global_speedup_set_rate(m_better_global_speedup_rate.load());
|
|
}
|
|
|
|
void Cracker::update_better_global_speedup_rate(double rate) {
|
|
m_better_global_speedup_rate.store(rate);
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
better_global_speedup_set_rate(rate);
|
|
}
|
|
}
|
|
|
|
void Cracker::disable_better_global_speedup() {
|
|
DISABLE(BETTER_GLOBAL_SPEEDUP);
|
|
better_global_speedup_set_rate(1.0);
|
|
}
|
|
|
|
void Cracker::skip_battle_celebrate_pause(bool need_pause) {
|
|
m_skip_battle_celebrate_need_pause.store(need_pause);
|
|
}
|
|
|
|
void Cracker::enable_skip_battle_celebrate() {
|
|
ENABLE(SKIP_BATTLE_CELEBRATE);
|
|
skip_battle_celebrate_set_duration(0.01);
|
|
}
|
|
|
|
void Cracker::disable_skip_battle_celebrate() {
|
|
DISABLE(SKIP_BATTLE_CELEBRATE);
|
|
skip_battle_celebrate_set_duration(3);
|
|
}
|
|
|
|
void Cracker::enable_monster_kill_self() {
|
|
ENABLE(MONSTER_KILL_SELF);
|
|
}
|
|
|
|
void Cracker::disable_monster_kill_self() {
|
|
DISABLE(MONSTER_KILL_SELF);
|
|
}
|
|
|
|
void Cracker::enable_fast_wave() {
|
|
ENABLE(FAST_WAVE);
|
|
}
|
|
|
|
void Cracker::disable_fast_wave() {
|
|
DISABLE(FAST_WAVE);
|
|
}
|
|
|
|
void Cracker::enable_exercise_more_power() {
|
|
ENABLE(EXERCISE_MORE_POWER);
|
|
}
|
|
|
|
void Cracker::update_exercise_more_power_rate(double rate) {
|
|
m_exercise_more_power_rate.store(rate);
|
|
}
|
|
|
|
void Cracker::disable_exercise_more_power() {
|
|
DISABLE(EXERCISE_MORE_POWER);
|
|
}
|
|
|
|
void Cracker::enable_exercise_god_mode() {
|
|
ENABLE(EXERCISE_GOD_MOD);
|
|
}
|
|
|
|
void Cracker::disable_exercise_god_mode() {
|
|
DISABLE(EXERCISE_GOD_MOD);
|
|
}
|
|
|
|
void Cracker::enable_global_speedup() {
|
|
m_global_speedup_timer.stop();
|
|
m_global_speedup_timer.setInterval([this]() {
|
|
get_Time_set_timeScale()(m_global_speedup_rate.load());
|
|
}, 500);
|
|
ENABLE(GLOBAL_SPEEDUP);
|
|
}
|
|
|
|
void Cracker::update_global_speedup_rate(float rate) {
|
|
m_global_speedup_rate.store(rate);
|
|
}
|
|
|
|
void Cracker::disable_global_speedup() {
|
|
m_global_speedup_timer.stop();
|
|
get_Time_set_timeScale()(1.0);
|
|
DISABLE(GLOBAL_SPEEDUP);
|
|
}
|
|
|
|
void Cracker::enable_gg_factor() {
|
|
ENABLE(GG_FACTOR);
|
|
}
|
|
|
|
void Cracker::disable_gg_factor() {
|
|
DISABLE(GG_FACTOR);
|
|
}
|
|
|
|
void Cracker::update_gg_factor(double factor) {
|
|
m_gg_factor = factor;
|
|
}
|
|
|
|
void Cracker::enable_opsi_fast_move() {
|
|
ENABLE(OPSI_FAST_MOVE);
|
|
}
|
|
|
|
void Cracker::disable_opsi_fast_move() {
|
|
DISABLE(OPSI_FAST_MOVE);
|
|
}
|
|
|
|
void Cracker::enable_no_emotion_warning() {
|
|
ENABLE(NO_EMOTION_WARNING);
|
|
}
|
|
|
|
void Cracker::disable_no_emotion_warning() {
|
|
DISABLE(NO_EMOTION_WARNING);
|
|
}
|
|
|
|
void Cracker::enable_no_bb_animation() {
|
|
ENABLE(NO_BB_ANIMATION);
|
|
}
|
|
|
|
void Cracker::disable_no_bb_animation() {
|
|
DISABLE(NO_BB_ANIMATION);
|
|
}
|
|
|
|
void Cracker::enable_fake_player() {
|
|
ENABLE(FAKE_PLAYER_INFO);
|
|
}
|
|
|
|
void Cracker::disable_fake_player() {
|
|
DISABLE(FAKE_PLAYER_INFO);
|
|
}
|
|
|
|
void Cracker::update_fake_player_info(const FakePlayerInfo& fake_info) {
|
|
m_fake_player_info = fake_info;
|
|
}
|
|
|
|
void Cracker::enable_remove_hard_mode_ship_type_limit() {
|
|
|
|
ENABLE(REMOVE_HARD_MODE_SHIP_TYPE_LIMIT);
|
|
}
|
|
|
|
void Cracker::disable_remove_hard_mode_ship_type_limit() {
|
|
DISABLE(REMOVE_HARD_MODE_SHIP_TYPE_LIMIT);
|
|
}
|
|
|
|
void Cracker::enable_remove_hard_mode_ship_properties_limit() {
|
|
ENABLE(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT);
|
|
}
|
|
|
|
void Cracker::disable_remove_hard_mode_ship_properties_limit() {
|
|
DISABLE(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT);
|
|
}
|
|
|
|
void Cracker::fast_stage_move_pause(bool need_pause) {
|
|
m_fast_stage_move_need_pause.store(need_pause);
|
|
}
|
|
|
|
void Cracker::enable_fast_stage_move() {
|
|
ENABLE(FAST_STAGE_MOVE_CRACK);
|
|
fast_stage_move_set_duration(0.0);
|
|
}
|
|
|
|
void Cracker::disable_fast_stage_move() {
|
|
DISABLE(FAST_STAGE_MOVE_CRACK);
|
|
fast_stage_move_set_duration(0.5);
|
|
}
|
|
|
|
void Cracker::update_global_ship_properties(const ShipProperties& properties) {
|
|
m_globle_ship_properties = properties;
|
|
}
|
|
|
|
void Cracker::enable_global_ship_properties_crack() {
|
|
ENABLE(GLOBAL_SHIP_PROPERTIES_CRACK);
|
|
}
|
|
|
|
void Cracker::disable_global_ship_properties_crack() {
|
|
DISABLE(GLOBAL_SHIP_PROPERTIES_CRACK);
|
|
}
|
|
|
|
void Cracker::fast_stage_move_set_duration(double duration) {
|
|
if (m_fast_stage_move_need_pause.load()) {
|
|
fast_stage_move_set_duration_with_pause(duration);
|
|
} else {
|
|
fast_stage_move_set_duration_without_pause(duration);
|
|
}
|
|
}
|
|
|
|
void Cracker::fast_stage_move_set_duration_with_pause(double duration) {
|
|
m_lua_state_pauser.do_when_paused([&] () {
|
|
m_state["ChapterConst"]["ShipStepDuration"] = duration;
|
|
m_state["ChapterConst"]["ShipStepQuickPlayScale"] = duration;
|
|
});
|
|
}
|
|
|
|
void Cracker::fast_stage_move_set_duration_without_pause(double duration) {
|
|
m_state["ChapterConst"]["ShipStepDuration"] = duration;
|
|
m_state["ChapterConst"]["ShipStepQuickPlayScale"] = duration;
|
|
}
|
|
|
|
void Cracker::skip_battle_celebrate_set_duration(double duration) {
|
|
if (m_skip_battle_celebrate_need_pause.load()) {
|
|
skip_battle_celebrate_set_duration_with_pause(duration);
|
|
} else {
|
|
skip_battle_celebrate_set_duration_without_pause(duration);
|
|
}
|
|
}
|
|
|
|
void Cracker::skip_battle_celebrate_set_duration_with_pause(double duration) {
|
|
m_lua_state_pauser.do_when_paused([&]() {
|
|
m_state["ys"]["Battle"]["BattleConfig"]["CelebrateDuration"] = duration;
|
|
});
|
|
}
|
|
|
|
void Cracker::skip_battle_celebrate_set_duration_without_pause(double duration) {
|
|
m_state["ys"]["Battle"]["BattleConfig"]["CelebrateDuration"] = duration;
|
|
}
|
|
|
|
void Cracker::print_table_field(std::vector<std::string>& path) {
|
|
Lua::Table t = m_state.globals();
|
|
for (const auto& p : path) {
|
|
t = t[p];
|
|
}
|
|
Utils::Lua::print_table_fields_type(t);
|
|
}
|
|
|
|
void Cracker::print_value(std::vector<std::string>& path) {
|
|
Lua::Table t = m_state.globals();
|
|
for (auto it = path.begin(); it != path.end() - 1; ++it) {
|
|
t = t[*it];
|
|
}
|
|
std::string key = path.back();
|
|
Lua::Object value = t[key];
|
|
auto type = value.get_type();
|
|
if (type == sol::type::number) {
|
|
SPDLOG_INFO("value: {}", value.as<double>());
|
|
} else if (type == sol::type::string) {
|
|
SPDLOG_INFO("value: {}", value.as<std::string>());
|
|
} else if (type == sol::type::boolean) {
|
|
SPDLOG_INFO("value: {}", value.as<bool>());
|
|
} else if (type == sol::type::nil) {
|
|
SPDLOG_INFO("value: nil");
|
|
} else if (type == sol::type::table) {
|
|
Lua::Table table = value.as<Lua::Table>();
|
|
Utils::Lua::print_table_fields_type(table);
|
|
}
|
|
}
|
|
|
|
void Cracker::better_global_speedup_pause(bool is_need) {
|
|
m_better_global_speedup_need_pause.store(is_need);
|
|
}
|
|
|
|
void Cracker::load_lua_resources() {
|
|
SPDLOG_INFO("Load lua resources");
|
|
|
|
SPDLOG_INFO("Load lua res");
|
|
m_lua_res.Clone = m_state["Clone"];
|
|
m_lua_res.Ship_getIntimacyLevel = m_state["Ship"]["getIntimacyLevel"];
|
|
m_lua_res.pg_intimacy_template = m_state["pg"]["intimacy_template"];
|
|
|
|
Lua::Table AttributeType = m_state["AttributeType"];
|
|
m_lua_res.AttributeType = {
|
|
.Durability = AttributeType.get<std::string>("Durability"),
|
|
.Cannon = AttributeType.get<std::string>("Cannon"),
|
|
.Torpedo = AttributeType.get<std::string>("Torpedo"),
|
|
.AntiAircraft = AttributeType.get<std::string>("AntiAircraft"),
|
|
.AntiSub = AttributeType.get<std::string>("AntiSub"),
|
|
.Air = AttributeType.get<std::string>("Air"),
|
|
.Reload = AttributeType.get<std::string>("Reload"),
|
|
.Hit = AttributeType.get<std::string>("Hit"),
|
|
.Dodge = AttributeType.get<std::string>("Dodge"),
|
|
};
|
|
m_lua_res.BattleResultMediator_GET_NEW_SHIP = m_state["BattleResultMediator"]["GET_NEW_SHIP"];
|
|
m_lua_res.NewBattleResultMediator_GET_NEW_SHIP = m_state["NewBattleResultMediator"]["GET_NEW_SHIP"];
|
|
m_lua_res.getProxy = m_state["getProxy"];
|
|
m_lua_res.ChapterProxy = m_state["ChapterProxy"];
|
|
m_lua_res.ChapterProxy_GetChapterAutoFlag = m_state["ChapterProxy"]["GetChapterAutoFlag"];
|
|
m_lua_res.ChapterProxy_SetChapterAutoFlag = m_state["ChapterProxy"]["SetChapterAutoFlag"];
|
|
m_lua_res.Chapter_getChapterCell = m_state["Chapter"]["getChapterCell"];
|
|
m_lua_res.LevelStageView_emit = m_state["LevelStageView"]["emit"];
|
|
m_lua_res.Chapter_emit = m_state["Chapter"]["emit"];
|
|
m_lua_res.ChapterConst_OpMove = m_state["ChapterConst"]["OpMove"];
|
|
m_lua_res.ChapterConst_CellFlagActive = m_state["ChapterConst"]["CellFlagActive"];
|
|
m_lua_res.ChapterConst_IsEnemyAttach = m_state["ChapterConst"]["IsEnemyAttach"];
|
|
m_lua_res.LevelMediator2_ON_OP = m_state["LevelMediator2"]["ON_OP"];
|
|
m_lua_res.Timer_New = m_state["Timer"]["New"];
|
|
m_lua_res.Timer_Start = m_state["Timer"]["Start"];
|
|
m_lua_res.ChapterConst_IsBossCell = m_state["ChapterConst"]["IsBossCell"];
|
|
m_lua_res.ChapterConst_CellFlagDisabled = m_state["ChapterConst"]["CellFlagDisabled"];
|
|
m_lua_res.Chapter_checkAnyInteractive = m_state["Chapter"]["checkAnyInteractive"];
|
|
m_lua_res.Chapter_GetFleetOfDuty = m_state["Chapter"]["GetFleetOfDuty"];
|
|
m_lua_res.Chapter_findPath = m_state["Chapter"]["findPath"];
|
|
m_lua_res.ChapterConst_SubjectPlayer = m_state["ChapterConst"]["SubjectPlayer"];
|
|
m_lua_res.Ship_ENERGY_LOW = m_state["Ship"]["ENERGY_LOW"];
|
|
|
|
SPDLOG_INFO("Load lua functions");
|
|
m_original.GetBattleCheckResult = m_state["GetBattleCheckResult"];
|
|
m_original.FinishStageCommand_GeneralPackage = m_state["FinishStageCommand"]["GeneralPackage"];
|
|
m_original.Ship_intimacyAdditions = m_state["Ship"]["intimacyAdditions"];
|
|
m_original.Ship_cosumeEnergy = m_state["Ship"]["cosumeEnergy"];
|
|
m_original.Ship_getEnergy = m_state["Ship"]["getEnergy"];
|
|
m_original.ys_Battle_BattleManualWeaponAutoBot_SetActive = m_state["ys"]["Battle"]["BattleManualWeaponAutoBot"]["SetActive"];
|
|
m_original.PlayerVitaeDetailPage_UpdateInfo = m_state["PlayerVitaeDetailPage"]["UpdateInfo"];
|
|
m_original.Chapter_getConfig = m_state["Chapter"]["getConfig"];
|
|
m_original.WorldFleetSelectLayer_CheckValid = m_state["WorldFleetSelectLayer"]["CheckValid"];
|
|
m_original.BossSingleBattleFleetSelectSubPanel_CheckValid = m_state["BossSingleBattleFleetSelectSubPanel"]["CheckValid"];
|
|
m_original.Chapter_IsEliteFleetLegal = m_state["Chapter"]["IsEliteFleetLegal"];
|
|
m_original.Ship_getShipProperties = m_state["Ship"]["getShipProperties"];
|
|
m_original.ys_Battle_BattleGateGuild_GeneralPackage = m_state["ys"]["Battle"]["BattleGateGuild"]["GeneralPackage"];
|
|
m_original.ys_Battle_BattleDataFunction_GetBuffTemplate = m_state["ys"]["Battle"]["BattleDataFunction"]["GetBuffTemplate"];
|
|
m_original.WorldConst_GetTerrainMoveStepDuration = m_state["WorldConst"]["GetTerrainMoveStepDuration"];
|
|
m_original.ys_Battle_BattleDataFunction_GetDungeonTmpDataByID = m_state["ys"]["Battle"]["BattleDataFunction"]["GetDungeonTmpDataByID"];
|
|
m_original.ys_Battle_BattleEnemyUnit_GetTemplate = m_state["ys"]["Battle"]["BattleEnemyUnit"]["GetTemplate"];
|
|
m_original.ys_Battle_BattleState_ExitBattle = m_state["ys"]["Battle"]["BattleState"]["ExitBattle"];
|
|
m_original.ys_Battle_BattleState_ScaleTimer = m_state["ys"]["Battle"]["BattleState"]["ScaleTimer"];
|
|
m_original.ShipSkin_IsShareSkin = m_state["ShipSkin"]["IsShareSkin"];
|
|
m_original.ShipSkin_CanUseShareSkinForShip = m_state["ShipSkin"]["CanUseShareSkinForShip"];
|
|
m_original.ShipSkinProxy_hasSkin = m_state["ShipSkinProxy"]["hasSkin"];
|
|
m_original.ShipSkinProxy_hasNonLimitSkin = m_state["ShipSkinProxy"]["hasNonLimitSkin"];
|
|
m_original.pg_ConnectionMgr_Send = m_state["pg"]["ConnectionMgr"]["Send"];
|
|
m_original.Ship_getSkinId = m_state["Ship"]["getSkinId"];
|
|
m_original.WorldMap_CanAutoFight = m_state["WorldMap"]["CanAutoFight"];
|
|
m_original.WorldMap_UpdateVisionFlag = m_state["WorldMap"]["UpdateVisionFlag"];
|
|
m_original.NewBattleResultDisplayAwardPage_ShowShips = m_state["NewBattleResultDisplayAwardPage"]["ShowShips"];
|
|
m_original.BaseUI_emit = m_state["BaseUI"]["emit"];
|
|
m_original.Chapter_CanActivateAutoFight = m_state["Chapter"]["CanActivateAutoFight"];
|
|
m_original.Chapter_IsAutoFight = m_state["Chapter"]["IsAutoFight"];
|
|
m_original.Chapter_IsSkipPrecombat = m_state["Chapter"]["IsSkipPrecombat"];
|
|
m_original.Chapter_writeBack = m_state["Chapter"]["writeBack"];
|
|
m_original.LevelStageView_tryAutoTrigger = m_state["LevelStageView"]["tryAutoTrigger"];
|
|
m_original.LevelStageView_TryAutoFight = m_state["LevelStageView"]["TryAutoFight"];
|
|
m_original.Story_Ctor = m_state["Story"]["Ctor"];
|
|
m_original.Fleet_EnergyCheck = m_state["Fleet"]["EnergyCheck"];
|
|
m_original.ContinuousOperationRuntimeData_ConsumeBattleTime = m_state["ContinuousOperationRuntimeData"]["ConsumeBattleTime"];
|
|
m_original.ActivityProxy_UseContinuousTime = m_state["ActivityProxy"]["UseContinuousTime"];
|
|
}
|
|
|
|
void Cracker::hook_all_lua_functions() {
|
|
SPDLOG_INFO("Hook lua functions");
|
|
|
|
// infinite_battle
|
|
m_state["ContinuousOperationRuntimeData"]["ConsumeBattleTime"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(ContinuousOperationRuntimeData.ConsumeBattleTime);
|
|
if (IS_ENABLED(INFINITE_BATTLE)) {
|
|
return;
|
|
}
|
|
m_original.ContinuousOperationRuntimeData_ConsumeBattleTime(L, args);
|
|
};
|
|
|
|
m_state["ActivityProxy"]["UseContinuousTime"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(ActivityProxy.UseContinuousTime);
|
|
if (IS_ENABLED(INFINITE_BATTLE)) {
|
|
return;
|
|
}
|
|
m_original.ActivityProxy_UseContinuousTime(L, args);
|
|
};
|
|
|
|
// skip_story
|
|
m_state["Story"]["Ctor"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(Story.Ctor);
|
|
m_original.Story_Ctor(L, args);
|
|
if (IS_ENABLED(SKIP_STORY)) {
|
|
Lua::Table self = args[0];
|
|
self["skipAll"] = true;
|
|
self["isAuto"] = false;
|
|
}
|
|
};
|
|
|
|
// chapter_auto_clear
|
|
m_state["LevelStageView"]["TryAutoFight"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(LevelStageView.TryAutoFight);
|
|
if (!IS_ENABLED(CHAPTER_AUTO_CLEAR)) {
|
|
m_original.LevelStageView_TryAutoFight(L, args);
|
|
return;
|
|
}
|
|
my_LevelStageView_TryAutoFight(L, args);
|
|
};
|
|
|
|
// chapter_auto_ambush
|
|
m_state["LevelStageView"]["tryAutoTrigger"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(LevelStageView.tryAutoTrigger);
|
|
if (!IS_ENABLED(CHAPTER_AUTO_AMBUSH)) {
|
|
return m_original.LevelStageView_tryAutoTrigger(L, args);
|
|
}
|
|
|
|
Lua::Table self = args[0];
|
|
std::optional<Lua::Table> chapterVO = self["contextData"]["chapterVO"];
|
|
|
|
if (chapterVO.has_value()) {
|
|
auto& vo = chapterVO.value();
|
|
Lua::Object row = vo["fleet"]["line"]["row"];
|
|
Lua::Object column = vo["fleet"]["line"]["column"];
|
|
|
|
std::optional<Lua::Table> cell = m_lua_res.Chapter_getChapterCell(L, vo, row, column);
|
|
if (cell.has_value()) {
|
|
auto& cell_v = cell.value();
|
|
int attachment = cell_v["attachment"];
|
|
int flag = cell_v["flag"];
|
|
|
|
if (attachment == 5 && flag == 2) {
|
|
Lua::Table trigger_arg = m_state.create_table();
|
|
|
|
int fleet_id = vo["fleet"]["id"];
|
|
trigger_arg["type"] = 4;
|
|
trigger_arg["id"] = fleet_id;
|
|
trigger_arg["arg1"] = 1;
|
|
|
|
m_lua_res.LevelStageView_emit(L, self, sol::make_object(L, "LevelMediator2:ON_OP"), trigger_arg);
|
|
return sol::make_object(L, true);
|
|
}
|
|
}
|
|
}
|
|
return m_original.LevelStageView_tryAutoTrigger(L, args);
|
|
};
|
|
|
|
// chapter_auto_next_battle
|
|
m_state["Chapter"]["writeBack"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(Chapter.writeBack);
|
|
|
|
if (!IS_ENABLED(CHAPTER_AUTO_NEXT_BATTLE)) {
|
|
m_original.Chapter_writeBack(L, args);
|
|
return;
|
|
}
|
|
|
|
m_original.Chapter_writeBack(L, args);
|
|
|
|
bool is_win = args[1];
|
|
if (!is_win) {
|
|
return;
|
|
}
|
|
|
|
Lua::Table self = args[0];
|
|
Lua::Object chapter_proxy = m_lua_res.getProxy(L, m_lua_res.ChapterProxy);
|
|
int id = self["id"];
|
|
m_lua_res.ChapterProxy_SetChapterAutoFlag(L, chapter_proxy, id, true);
|
|
};
|
|
|
|
// chapter_skip_precombat
|
|
m_state["Chapter"]["IsSkipPrecombat"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Chapter.IsSkipPrecombat);
|
|
if (!IS_ENABLED(CHAPTER_SKIP_PRECOMBAT)) {
|
|
return m_original.Chapter_IsSkipPrecombat(L, args);
|
|
}
|
|
return sol::make_object(L, true);
|
|
};
|
|
|
|
// force_enable_auto_fight
|
|
m_state["Chapter"]["CanActivateAutoFight"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Chapter.CanActivateAutoFight);
|
|
if (!IS_ENABLED(CHAPTER_FORCE_ENABLE_AUTO_FIGHT)) {
|
|
return m_original.Chapter_CanActivateAutoFight(L, args);
|
|
}
|
|
return sol::make_object(L, true);
|
|
};
|
|
|
|
m_state["Chapter"]["IsAutoFight"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Chapter.IsAutoFight);
|
|
if (!IS_ENABLED(CHAPTER_FORCE_ENABLE_AUTO_FIGHT)) {
|
|
return m_original.Chapter_IsAutoFight(L, args);
|
|
}
|
|
|
|
Lua::Object chapter_proxy = m_lua_res.getProxy(L, m_lua_res.ChapterProxy);
|
|
|
|
int id = args[0].as<Lua::Table>()["id"];
|
|
Lua::Object flag = m_lua_res.ChapterProxy_GetChapterAutoFlag(L, chapter_proxy, id);
|
|
|
|
auto flag_type = flag.get_type();
|
|
if (flag_type == sol::type::nil) {
|
|
return sol::make_object(L, true);
|
|
} else if (flag_type == sol::type::number) {
|
|
return sol::make_object(L, flag.as<int>() != 0);
|
|
} else {
|
|
return sol::make_object(L, false);
|
|
}
|
|
return sol::make_object(L, false);
|
|
};
|
|
|
|
// skip_ship_gain_show
|
|
m_state["NewBattleResultDisplayAwardPage"]["ShowShips"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(NewBattleResultDisplayAwardPage.ShowShips);
|
|
if (!IS_ENABLED(SKIP_SHIP_GAIN_SHOW)) {
|
|
m_original.NewBattleResultDisplayAwardPage_ShowShips(L, args);
|
|
return;
|
|
}
|
|
|
|
Lua::Function callback = args[2];
|
|
callback(L);
|
|
};
|
|
|
|
m_state["BaseUI"]["emit"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(BaseUI.emit);
|
|
if (!IS_ENABLED(SKIP_SHIP_GAIN_SHOW)) {
|
|
m_original.BaseUI_emit(L, args);
|
|
return;
|
|
}
|
|
|
|
std::string event_name = args[1];
|
|
if (event_name == m_lua_res.BattleResultMediator_GET_NEW_SHIP
|
|
|| event_name == m_lua_res.NewBattleResultMediator_GET_NEW_SHIP) {
|
|
for (int i = 2; i <= args.size(); ++i) {
|
|
Lua::Object obj = args[i];
|
|
if (obj.get_type() == sol::type::function) {
|
|
obj.as<sol::function>()();
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
m_original.BaseUI_emit(L, args);
|
|
};
|
|
|
|
// opsi_force_auto
|
|
m_state["WorldMap"]["CanAutoFight"] = [this](sol::this_state L, Lua::VariadicArgs args) -> bool {
|
|
if (!IS_ENABLED(OPSI_FORCE_AUTO)) {
|
|
return m_original.WorldMap_CanAutoFight(L, args);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// opsi_no_map_fog
|
|
m_state["WorldMap"]["UpdateVisionFlag"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
if (!IS_ENABLED(OPSI_NO_MAP_FOG)) {
|
|
m_original.WorldMap_UpdateVisionFlag(L, args);
|
|
return;
|
|
}
|
|
auto new_args = std::vector<Lua::Object>();
|
|
new_args.push_back(args[0]);
|
|
new_args.push_back(sol::make_object(L, true));
|
|
m_original.WorldMap_UpdateVisionFlag(L, sol::as_args(new_args));
|
|
};
|
|
|
|
// all_skin
|
|
class AlwaysOn {
|
|
public:
|
|
AlwaysOn(Cracker* cracker, Lua::Function& orig_func):m_cracker(cracker), m_orig_func(orig_func) {}
|
|
bool operator()(sol::this_state L, Lua::VariadicArgs args) {
|
|
if (m_cracker->m_flag.ALL_SKIN.load()) {
|
|
return true;
|
|
}
|
|
return m_orig_func(L, args);
|
|
}
|
|
private:
|
|
Cracker* m_cracker;
|
|
Lua::Function& m_orig_func;
|
|
};
|
|
|
|
m_state["ShipSkin"]["IsShareSkin"] = AlwaysOn(this, m_original.ShipSkin_IsShareSkin);
|
|
m_state["ShipSkin"]["CanUseShareSkinForShip"] = AlwaysOn(this, m_original.ShipSkin_CanUseShareSkinForShip);
|
|
m_state["ShipSkinProxy"]["hasSkin"] = AlwaysOn(this, m_original.ShipSkinProxy_hasSkin);
|
|
m_state["ShipSkinProxy"]["hasNonLimitSkin"] = AlwaysOn(this, m_original.ShipSkinProxy_hasNonLimitSkin);
|
|
|
|
m_state["pg"]["ConnectionMgr"]["Send"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(pg.ConnectionMgr.Send);
|
|
if (IS_ENABLED(ALL_SKIN)) {
|
|
int req_id = args[1];
|
|
if (req_id == 12202) {
|
|
Lua::Table req_arg = args[2];
|
|
int ship_id = req_arg["ship_id"];
|
|
int skin_id = req_arg["skin_id"];
|
|
|
|
SkinCache::get_instance().save(ship_id, skin_id);
|
|
|
|
Lua::Table fake_result = m_state.create_table();
|
|
fake_result["result"] = 0;
|
|
|
|
Lua::Function callback = args[4];
|
|
callback(L, fake_result);
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
m_original.pg_ConnectionMgr_Send(L, args);
|
|
};
|
|
|
|
m_state["Ship"]["getSkinId"] = [this](sol::this_state L, Lua::VariadicArgs args) -> int {
|
|
CALLED(Ship.getSkinId);
|
|
|
|
if (!IS_ENABLED(ALL_SKIN)) {
|
|
return m_original.Ship_getSkinId(L, args);
|
|
}
|
|
|
|
Lua::Table self = args[0];
|
|
int ship_id = self["id"];
|
|
|
|
auto& skin_cache = SkinCache::get_instance();
|
|
if (skin_cache.has_ship(ship_id)) {
|
|
return skin_cache.get_skin(ship_id);
|
|
}
|
|
return m_original.Ship_getSkinId(L, args);
|
|
};
|
|
|
|
// better_global_speedup
|
|
m_state["ys"]["Battle"]["BattleState"]["ExitBattle"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
m_original.ys_Battle_BattleState_ExitBattle(L, args);
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
better_global_speedup_pause(false);
|
|
better_global_speedup_set_rate(m_better_global_speedup_rate.load());
|
|
}
|
|
};
|
|
|
|
m_state["ys"]["Battle"]["BattleState"]["ScaleTimer"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
m_original.ys_Battle_BattleState_ScaleTimer(L, args);
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
better_global_speedup_pause(false);
|
|
better_global_speedup_set_rate(m_better_global_speedup_rate.load());
|
|
}
|
|
};
|
|
|
|
// monster_kill_self
|
|
m_state["ys"]["Battle"]["BattleEnemyUnit"]["GetTemplate"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(ys.Battle.BattleEnemyUnit.GetTemplate);
|
|
if (!IS_ENABLED(MONSTER_KILL_SELF)) {
|
|
return m_original.ys_Battle_BattleEnemyUnit_GetTemplate(L, args);
|
|
}
|
|
|
|
Lua::Table result_original = m_original.ys_Battle_BattleEnemyUnit_GetTemplate(L, args);
|
|
Lua::Table result = m_lua_res.Clone(result_original);
|
|
|
|
Lua::Table buff_list = m_state.create_table();
|
|
|
|
Lua::Table buff1 = m_state.create_table();
|
|
buff1["ID"] = 201229;
|
|
buff1["LV"] = 1;
|
|
buff_list.add(buff1);
|
|
|
|
Lua::Table buff2 = m_state.create_table();
|
|
buff2["ID"] = 800382;
|
|
buff2["LV"] = 1;
|
|
buff_list.add(buff2);
|
|
|
|
result["buff_list"] = buff_list;
|
|
|
|
return result;
|
|
};
|
|
|
|
// fast_wave
|
|
m_state["ys"]["Battle"]["BattleDataFunction"]["GetDungeonTmpDataByID"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Table {
|
|
CALLED(ys.Battle.BattleDataFunction.GetDungeonTmpDataByID);
|
|
if (!IS_ENABLED(FAST_WAVE)) {
|
|
return m_original.ys_Battle_BattleDataFunction_GetDungeonTmpDataByID(L, args);
|
|
}
|
|
|
|
Lua::Table result_original = m_original.ys_Battle_BattleDataFunction_GetDungeonTmpDataByID(L, args);
|
|
Lua::Table result = m_lua_res.Clone(result_original);
|
|
Lua::Table stages = result["stages"];
|
|
|
|
for (int i = 1; i <= stages.size(); ++i) {
|
|
Lua::Table stage = stages[i];
|
|
Lua::Table waves = stage["waves"];
|
|
|
|
for(int j = 1; j <= waves.size(); ++j) {
|
|
Lua::Table wave = waves[j];
|
|
|
|
sol::optional<Lua::Table> preWaves = wave["preWaves"];
|
|
if (preWaves.has_value()) {
|
|
preWaves.value().clear();
|
|
}
|
|
sol::optional<Lua::Table> triggerParams = wave["triggerParams"];
|
|
if (triggerParams.has_value()) {
|
|
triggerParams.value()["timeout"] = 0.1;
|
|
}
|
|
sol::optional<Lua::Table> airFighterTable = wave["airFighter"];
|
|
if (airFighterTable.has_value()) {
|
|
auto& airFighters = airFighterTable.value();
|
|
for (int k = 1; k <= airFighters.size(); ++k) {
|
|
Lua::Table airFighter = airFighters[k];
|
|
airFighter["interval"] = 0;
|
|
airFighter["onceNumber"] = 0;
|
|
airFighter["totalNumber"] = 0;
|
|
airFighter["delay"] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
// enable_global_speedup
|
|
m_state["GetBattleCheckResult"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(GetBattleCheckResult);
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
goto hook_handler;
|
|
}
|
|
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
if (IS_ENABLED(MONSTER_KILL_SELF)) {
|
|
goto original_ret;
|
|
} else {
|
|
goto hook_handler;
|
|
}
|
|
}
|
|
|
|
original_ret:
|
|
return m_original.GetBattleCheckResult(L, args);
|
|
|
|
hook_handler:
|
|
|
|
double speedup_rate;
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_global_speedup_rate.load();
|
|
} else if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_better_global_speedup_rate.load();
|
|
} else {
|
|
return m_original.GetBattleCheckResult(L, args);;
|
|
}
|
|
|
|
double total_time = args[2];
|
|
std::vector<Lua::Object> new_args(args.begin(), args.end());
|
|
new_args[2] = sol::make_object(L, total_time / speedup_rate);
|
|
return m_original.GetBattleCheckResult(L, sol::as_args(new_args));
|
|
};
|
|
|
|
m_state["ys"]["Battle"]["BattleGateGuild"]["GeneralPackage"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Table {
|
|
CALLED(ys.Battle.BattleGateGuild.GeneralPackage);
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
goto hook_handler;
|
|
}
|
|
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
if (IS_ENABLED(MONSTER_KILL_SELF)) {
|
|
goto original_ret;
|
|
} else {
|
|
goto hook_handler;
|
|
}
|
|
}
|
|
|
|
original_ret:
|
|
return m_original.ys_Battle_BattleGateGuild_GeneralPackage(L, args);
|
|
|
|
hook_handler:
|
|
|
|
Lua::Table ret = m_original.ys_Battle_BattleGateGuild_GeneralPackage(args);
|
|
|
|
double speedup_rate;
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_global_speedup_rate.load();
|
|
} else if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_better_global_speedup_rate.load();
|
|
} else {
|
|
return ret;
|
|
}
|
|
|
|
double total_time = ret["total_time"];
|
|
ret["total_time"] = total_time / speedup_rate;
|
|
return ret;
|
|
};
|
|
|
|
m_state["FinishStageCommand"]["GeneralPackage"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Table {
|
|
CALLED(FinishStageCommand.GeneralPackage);
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
goto hook_handler;
|
|
}
|
|
|
|
if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
if (IS_ENABLED(MONSTER_KILL_SELF)) {
|
|
goto original_ret;
|
|
} else {
|
|
goto hook_handler;
|
|
}
|
|
}
|
|
|
|
if (IS_ENABLED(NO_DAMAGE)) {
|
|
goto hook_handler;
|
|
}
|
|
|
|
original_ret:
|
|
return m_original.FinishStageCommand_GeneralPackage(L, args);
|
|
|
|
hook_handler:
|
|
|
|
Lua::Table ret;
|
|
if (IS_ENABLED(NO_DAMAGE)) {
|
|
Lua::Table battle_into = args[0];
|
|
Lua::Table battle_statistics = battle_into["statistics"];
|
|
Lua::Table battle_ship_info = args[1];
|
|
for(int i = 1; i <= battle_ship_info.size(); ++i) {
|
|
double ship_id = battle_ship_info[i]["id"];
|
|
Lua::Table item = battle_statistics[ship_id];
|
|
item["output"] = 0.0;
|
|
item["damage"] = 0.0;
|
|
item["maxDamageOnce"] = 0.0;
|
|
item["kill_count"] = 0.0;
|
|
}
|
|
|
|
std::vector<Lua::Object> new_args(args.begin(), args.end());
|
|
new_args[0] = sol::make_object(L, battle_into);
|
|
ret = m_original.FinishStageCommand_GeneralPackage(L, sol::as_args(new_args));
|
|
} else {
|
|
ret = m_original.FinishStageCommand_GeneralPackage(L, args);
|
|
}
|
|
|
|
double speedup_rate;
|
|
if (IS_ENABLED(GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_global_speedup_rate.load();
|
|
} else if (IS_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
speedup_rate = m_better_global_speedup_rate.load();
|
|
} else {
|
|
return ret;
|
|
}
|
|
|
|
double total_time = ret["total_time"];
|
|
ret["total_time"] = total_time / speedup_rate;
|
|
return ret;
|
|
};
|
|
|
|
// enable_gg_factor
|
|
m_state["Ship"]["intimacyAdditions"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Ship.intimacyAdditions);
|
|
if (!IS_ENABLED(GG_FACTOR)) {
|
|
return m_original.Ship_intimacyAdditions(L, args);
|
|
}
|
|
|
|
if (args.size() < 2) {
|
|
return m_original.Ship_intimacyAdditions(L, args);
|
|
}
|
|
|
|
Lua::Table self = args[0];
|
|
int intimacy_level = m_lua_res.Ship_getIntimacyLevel(self);
|
|
Lua::Table attr_bonus_table = m_lua_res.pg_intimacy_template.get<Lua::Table>(intimacy_level);
|
|
double attr_bonus = attr_bonus_table.get<double>("attr_bonus");
|
|
double calculated_attr_bonus = attr_bonus * 0.0001;
|
|
|
|
Lua::Table attributes = args[1];
|
|
for (auto& [attr_name, attr_value] : attributes) {
|
|
if (attr_name.get_type() == sol::type::string) {
|
|
std::string attr_name_str = attr_name.as<std::string>();
|
|
const auto& attr = m_lua_res.AttributeType;
|
|
if (
|
|
attr_name_str == attr.Durability
|
|
|| attr_name_str == attr.Cannon
|
|
|| attr_name_str == attr.Torpedo
|
|
|| attr_name_str == attr.AntiAircraft
|
|
|| attr_name_str == attr.AntiSub
|
|
|| attr_name_str == attr.Air
|
|
|| attr_name_str == attr.Reload
|
|
|| attr_name_str == attr.Hit
|
|
|| attr_name_str == attr.Dodge
|
|
) {
|
|
double old_value = attributes[attr_name_str];
|
|
attributes[attr_name_str] = old_value * (calculated_attr_bonus + m_gg_factor);
|
|
}
|
|
}
|
|
}
|
|
return sol::nil;
|
|
};
|
|
|
|
// enable_no_emotion_warning
|
|
m_state["Ship"]["cosumeEnergy"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Ship.cosumeEnergy);
|
|
if (!IS_ENABLED(NO_EMOTION_WARNING)) {
|
|
return m_original.Ship_cosumeEnergy(L, args);
|
|
}
|
|
return sol::nil;
|
|
};
|
|
m_state["Ship"]["getEnergy"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Ship.getEnergy);
|
|
if (!IS_ENABLED(NO_EMOTION_WARNING)) {
|
|
return m_original.Ship_getEnergy(L, args);
|
|
}
|
|
return sol::make_object(L, 150);
|
|
};
|
|
m_state["Fleet"]["EnergyCheck"] = [this](sol::this_state L, Lua::VariadicArgs args) {
|
|
CALLED(Fleet.EnergyCheck);
|
|
|
|
bool no_emotion_warning_enabled = IS_ENABLED(NO_EMOTION_WARNING);
|
|
|
|
if (no_emotion_warning_enabled) {
|
|
m_state["Ship"]["ENERGY_LOW"] = -1;
|
|
}
|
|
|
|
m_original.Fleet_EnergyCheck(L, args);
|
|
|
|
if (no_emotion_warning_enabled) {
|
|
m_state["Ship"]["ENERGY_LOW"] = m_lua_res.Ship_ENERGY_LOW;
|
|
}
|
|
};
|
|
|
|
// enable_no_bb_animation
|
|
m_state["ys"]["Battle"]["BattleManualWeaponAutoBot"]["SetActive"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(ys.Battle.BattleManualWeaponAutoBot.SetActive);
|
|
if (!IS_ENABLED(NO_BB_ANIMATION)) {
|
|
return m_original.ys_Battle_BattleManualWeaponAutoBot_SetActive(L, args);
|
|
}
|
|
if (args.size() < 3) {
|
|
return m_original.ys_Battle_BattleManualWeaponAutoBot_SetActive(L, args);
|
|
}
|
|
|
|
std::vector<Lua::Object> new_args(args.begin(), args.end());
|
|
new_args[2] = sol::make_object(L, false);
|
|
Lua::Object res = m_original.ys_Battle_BattleManualWeaponAutoBot_SetActive(sol::as_args(new_args));
|
|
return res;
|
|
};
|
|
|
|
// enable_fake_player
|
|
m_state["PlayerVitaeDetailPage"]["UpdateInfo"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(PlayerVitaeDetailPage.UpdateInfo);
|
|
if (!IS_ENABLED(FAKE_PLAYER_INFO)) {
|
|
return m_original.PlayerVitaeDetailPage_UpdateInfo(L, args);
|
|
}
|
|
|
|
Lua::Object res = m_original.PlayerVitaeDetailPage_UpdateInfo(args);
|
|
|
|
Lua::Table t = args[0];
|
|
|
|
if (!m_fake_player_info.name.empty()) {
|
|
t["nameTxt"]["text"] = m_fake_player_info.name;
|
|
}
|
|
if (!m_fake_player_info.level.empty()) {
|
|
t["levelTxt"]["text"] = "LV." + m_fake_player_info.level;
|
|
}
|
|
if (!m_fake_player_info.id.empty()) {
|
|
t["idTxt"]["text"] = m_fake_player_info.id;
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
// enable_remove_hard_mode_ship_type_limit
|
|
m_state["Chapter"]["getConfig"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Chapter.getConfig);
|
|
if (!IS_ENABLED(REMOVE_HARD_MODE_SHIP_TYPE_LIMIT)) {
|
|
return m_original.Chapter_getConfig(L, args);
|
|
}
|
|
|
|
bool limitation = false;
|
|
if (args.size() == 2) {
|
|
Lua::Object first_arg = args[1];
|
|
if (first_arg.get_type() == sol::type::string && first_arg.as<std::string>() == "limitation") {
|
|
limitation = true;
|
|
}
|
|
}
|
|
|
|
Lua::Object res = m_original.Chapter_getConfig(L, args);
|
|
|
|
if (limitation) {
|
|
sol::table table = res;
|
|
clear_hard_mode_ship_properties_limit(table);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
// enable_remove_hard_mode_ship_properties_limit
|
|
m_state["WorldFleetSelectLayer"]["CheckValid"] = [this](sol::this_state L, Lua::VariadicArgs args) -> bool {
|
|
CALLED(WorldFleetSelectLayer.CheckValid);
|
|
if (!IS_ENABLED(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT)) {
|
|
return m_original.WorldFleetSelectLayer_CheckValid(L, args);
|
|
}
|
|
return true;
|
|
};
|
|
m_state["BossSingleBattleFleetSelectSubPanel"]["CheckValid"] = [this](sol::this_state L, Lua::VariadicArgs args) -> bool {
|
|
CALLED(BossSingleBattleFleetSelectSubPanel.CheckValid);
|
|
if (!IS_ENABLED(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT)) {
|
|
return m_original.BossSingleBattleFleetSelectSubPanel_CheckValid(L, args);
|
|
}
|
|
return true;
|
|
};
|
|
m_state["Chapter"]["IsEliteFleetLegal"] = [this](sol::this_state L, Lua::VariadicArgs args) -> bool {
|
|
CALLED(Chapter.IsEliteFleetLegal);
|
|
if (!IS_ENABLED(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT)) {
|
|
return m_original.Chapter_IsEliteFleetLegal(L, args);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// enable_global_ship_properties_crack
|
|
m_state["Ship"]["getShipProperties"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(Ship.getShipProperties);
|
|
if (!IS_ENABLED(GLOBAL_SHIP_PROPERTIES_CRACK)) {
|
|
return m_original.Ship_getShipProperties(L, args);
|
|
}
|
|
Lua::Table properties = m_original.Ship_getShipProperties(L, args);
|
|
modify_ship_properties(properties, m_globle_ship_properties);
|
|
return properties;
|
|
};
|
|
|
|
// exercise
|
|
m_state["ys"]["Battle"]["BattleDataFunction"]["GetBuffTemplate"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Table {
|
|
CALLED(ys.Battle.BattleDataFunction.GetBuffTemplate);
|
|
|
|
auto is_enabled_EXERCISE_GOD_MOD = IS_ENABLED(EXERCISE_GOD_MOD);
|
|
auto is_enabled_EXERCISE_MORE_POWER = IS_ENABLED(EXERCISE_MORE_POWER);
|
|
auto is_enabled_MONSTER_KILL_SELF = IS_ENABLED(MONSTER_KILL_SELF);
|
|
|
|
if (!is_enabled_EXERCISE_GOD_MOD && !is_enabled_EXERCISE_MORE_POWER && !is_enabled_MONSTER_KILL_SELF) {
|
|
return m_original.ys_Battle_BattleDataFunction_GetBuffTemplate(L, args);
|
|
}
|
|
|
|
double buff_id = args[0];
|
|
Lua::Table buff_original = m_original.ys_Battle_BattleDataFunction_GetBuffTemplate(L, args);
|
|
Lua::Table buff = m_lua_res.Clone(buff_original);
|
|
if (buff_id == 19) { // buff_19
|
|
sol::table effect_list = m_state.create_table();
|
|
|
|
if (is_enabled_EXERCISE_GOD_MOD) {
|
|
sol::table entry1 = m_state.create_table();
|
|
entry1["type"] = "BattleBuffCastSkill";
|
|
|
|
sol::table trigger1 = m_state.create_table();
|
|
trigger1.add("onBeforeFatalDamage");
|
|
entry1["trigger"] = trigger1;
|
|
|
|
sol::table arg_list1 = m_state.create_table();
|
|
arg_list1["skill_id"] = 11011;
|
|
arg_list1["target"] = "TargetSelf";
|
|
entry1["arg_list"] = arg_list1;
|
|
|
|
sol::table entry2 = m_state.create_table();
|
|
entry2["type"] = "BattleBuffCancelBuff";
|
|
|
|
sol::table trigger2 = m_state.create_table();
|
|
trigger2.add("onBeforeFatalDamage");
|
|
entry2["trigger"] = trigger2;
|
|
|
|
sol::table arg_list2 = m_state.create_table();
|
|
arg_list2["count"] = INT_MAX;
|
|
entry2["arg_list"] = arg_list2;
|
|
|
|
sol::table entry3 = m_state.create_table();
|
|
entry3["type"] = "BattleBuffAddBuff";
|
|
|
|
sol::table trigger3 = m_state.create_table();
|
|
trigger3.add("onRemove");
|
|
entry3["trigger"] = trigger3;
|
|
|
|
sol::table arg_list3 = m_state.create_table();
|
|
arg_list3["buff_id"] = 11016;
|
|
entry3["arg_list"] = arg_list3;
|
|
|
|
sol::table entry4 = m_state.create_table();
|
|
entry4["type"] = "BattleBuffAddAttr";
|
|
|
|
sol::table trigger4 = m_state.create_table();
|
|
trigger4.add("onAttach");
|
|
entry4["trigger"] = trigger4;
|
|
|
|
sol::table arg_list4 = m_state.create_table();
|
|
arg_list4["number"] = 1;
|
|
arg_list4["target"] = "TargetSelf";
|
|
arg_list4["attr"] = "isInvincible";
|
|
entry4["arg_list"] = arg_list4;
|
|
|
|
effect_list.add(entry1);
|
|
effect_list.add(entry2);
|
|
effect_list.add(entry3);
|
|
effect_list.add(entry4);
|
|
}
|
|
|
|
if (is_enabled_EXERCISE_MORE_POWER) {
|
|
sol::table entry = m_state.create_table();
|
|
entry["type"] = "BattleBuffAddBulletAttr";
|
|
|
|
sol::table trigger = m_state.create_table();
|
|
trigger.add("onBulletCreate");
|
|
entry["trigger"] = trigger;
|
|
|
|
sol::table arg_list = m_state.create_table();
|
|
arg_list["number"] = m_exercise_more_power_rate.load();
|
|
arg_list["attr"] = "damageRatioBullet";
|
|
entry["arg_list"] = arg_list;
|
|
|
|
effect_list.add(entry);
|
|
}
|
|
|
|
if (is_enabled_EXERCISE_GOD_MOD || is_enabled_EXERCISE_MORE_POWER) {
|
|
buff["effect_list"] = effect_list;
|
|
}
|
|
} else if (buff_id == 800382) {
|
|
if (is_enabled_MONSTER_KILL_SELF) {
|
|
buff["effect_list"][1]["arg_list"]["number"] = -9999999;
|
|
}
|
|
}
|
|
return buff;
|
|
};
|
|
|
|
m_state["WorldConst"]["GetTerrainMoveStepDuration"] = [this](sol::this_state L, Lua::VariadicArgs args) -> Lua::Object {
|
|
CALLED(WorldConst.GetTerrainMoveStepDuration);
|
|
if (!IS_ENABLED(OPSI_FAST_MOVE)) {
|
|
return m_original.WorldConst_GetTerrainMoveStepDuration(L, args);
|
|
}
|
|
return sol::make_object(L, 0);
|
|
};
|
|
}
|
|
|
|
void Cracker::better_global_speedup_set_rate(double rate) {
|
|
if (m_better_global_speedup_need_pause.load()) {
|
|
better_global_speedup_set_rate_with_pause(rate);
|
|
} else {
|
|
better_global_speedup_set_rate_without_pause(rate);
|
|
}
|
|
}
|
|
|
|
void Cracker::better_global_speedup_set_rate_with_pause(double rate) {
|
|
m_lua_state_pauser.do_when_paused([&]() {
|
|
m_state["ys"]["Battle"]["BattleConfig"]["BASIC_TIME_SCALE"] = rate;
|
|
m_state["Time"]["timeScale"] = rate;
|
|
});
|
|
}
|
|
|
|
void Cracker::better_global_speedup_set_rate_without_pause(double rate) {
|
|
m_state["ys"]["Battle"]["BattleConfig"]["BASIC_TIME_SCALE"] = rate;
|
|
m_state["Time"]["timeScale"] = rate;
|
|
}
|
|
|
|
#define SET_CONFIG_FLAG(n) .n = m_flag.n.load()
|
|
|
|
Cracker::Config Cracker::get_config() {
|
|
Config config = {
|
|
.flag = {
|
|
SET_CONFIG_FLAG(HOOKED_LUA_FUNCTION_TRACE),
|
|
SET_CONFIG_FLAG(GLOBAL_SHIP_PROPERTIES_CRACK),
|
|
SET_CONFIG_FLAG(FAST_STAGE_MOVE_CRACK),
|
|
SET_CONFIG_FLAG(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT),
|
|
SET_CONFIG_FLAG(REMOVE_HARD_MODE_SHIP_TYPE_LIMIT),
|
|
SET_CONFIG_FLAG(FAKE_PLAYER_INFO),
|
|
SET_CONFIG_FLAG(NO_BB_ANIMATION),
|
|
SET_CONFIG_FLAG(NO_EMOTION_WARNING),
|
|
SET_CONFIG_FLAG(OPSI_FAST_MOVE),
|
|
SET_CONFIG_FLAG(GG_FACTOR),
|
|
SET_CONFIG_FLAG(GLOBAL_SPEEDUP),
|
|
SET_CONFIG_FLAG(EXERCISE_GOD_MOD),
|
|
SET_CONFIG_FLAG(EXERCISE_MORE_POWER),
|
|
SET_CONFIG_FLAG(FAST_WAVE),
|
|
SET_CONFIG_FLAG(MONSTER_KILL_SELF),
|
|
SET_CONFIG_FLAG(SKIP_BATTLE_CELEBRATE),
|
|
SET_CONFIG_FLAG(BETTER_GLOBAL_SPEEDUP),
|
|
SET_CONFIG_FLAG(NO_DAMAGE),
|
|
SET_CONFIG_FLAG(OPSI_FORCE_AUTO),
|
|
SET_CONFIG_FLAG(OPSI_NO_MAP_FOG),
|
|
SET_CONFIG_FLAG(SKIP_SHIP_GAIN_SHOW),
|
|
SET_CONFIG_FLAG(CHAPTER_FORCE_ENABLE_AUTO_FIGHT),
|
|
SET_CONFIG_FLAG(CHAPTER_SKIP_PRECOMBAT),
|
|
SET_CONFIG_FLAG(CHAPTER_AUTO_NEXT_BATTLE),
|
|
SET_CONFIG_FLAG(CHAPTER_AUTO_AMBUSH),
|
|
SET_CONFIG_FLAG(CHAPTER_AUTO_CLEAR),
|
|
SET_CONFIG_FLAG(SKIP_STORY),
|
|
SET_CONFIG_FLAG(INFINITE_BATTLE),
|
|
},
|
|
.globle_ship_properties = m_globle_ship_properties,
|
|
.global_speedup_rate = static_cast<int>(m_global_speedup_rate),
|
|
.gg_factor = m_gg_factor,
|
|
.exercise_more_power_rate = static_cast<int>(m_exercise_more_power_rate.load() * 100),
|
|
.better_global_speedup_rate = static_cast<int>(m_better_global_speedup_rate.load()),
|
|
};
|
|
return config;
|
|
}
|
|
|
|
#define IS_CONFIG_ENABLED(n) config.flag.n
|
|
|
|
void Cracker::apply_config(Config& config) {
|
|
if(IS_CONFIG_ENABLED(INFINITE_BATTLE)) {
|
|
enable_infinite_battle();
|
|
} else {
|
|
disable_infinite_battle();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(HOOKED_LUA_FUNCTION_TRACE)) {
|
|
enable_hooked_lua_function_trace();
|
|
} else {
|
|
disable_hooked_lua_function_trace();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(SKIP_STORY)) {
|
|
enable_skip_story();
|
|
} else {
|
|
disable_skip_story();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(CHAPTER_AUTO_CLEAR)) {
|
|
enable_chapter_auto_clear();
|
|
} else {
|
|
disable_chapter_auto_clear();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(CHAPTER_AUTO_AMBUSH)) {
|
|
enable_chapter_auto_ambush();
|
|
} else {
|
|
disable_chapter_auto_ambush();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(CHAPTER_SKIP_PRECOMBAT)) {
|
|
enable_chapter_skip_precombat();
|
|
} else {
|
|
disable_chapter_skip_precombat();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(CHAPTER_FORCE_ENABLE_AUTO_FIGHT)) {
|
|
enable_chapter_force_enable_auto_fight();
|
|
} else {
|
|
disable_chapter_force_enable_auto_fight();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(CHAPTER_AUTO_NEXT_BATTLE)) {
|
|
enable_chapter_auto_next_battle();
|
|
} else {
|
|
disable_chapter_auto_next_battle();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(SKIP_SHIP_GAIN_SHOW)) {
|
|
enable_skip_ship_gain_show();
|
|
} else {
|
|
disable_skip_ship_gain_show();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(OPSI_FORCE_AUTO)) {
|
|
enable_opsi_force_auto();
|
|
} else {
|
|
disable_opsi_force_auto();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(OPSI_NO_MAP_FOG)) {
|
|
enable_opsi_no_map_fog();
|
|
} else {
|
|
disable_opsi_no_map_fog();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(ALL_SKIN)) {
|
|
enable_all_skin();
|
|
} else {
|
|
disable_all_skin();
|
|
}
|
|
|
|
if(IS_CONFIG_ENABLED(GLOBAL_SHIP_PROPERTIES_CRACK)) {
|
|
update_global_ship_properties(config.globle_ship_properties);
|
|
enable_global_ship_properties_crack();
|
|
} else {
|
|
disable_global_ship_properties_crack();
|
|
}
|
|
if(IS_CONFIG_ENABLED(FAST_STAGE_MOVE_CRACK)) {
|
|
enable_fast_stage_move();
|
|
} else {
|
|
disable_fast_stage_move();
|
|
}
|
|
if(IS_CONFIG_ENABLED(REMOVE_HARD_MODE_SHIP_PROPERTIES_LIMIT)) {
|
|
enable_remove_hard_mode_ship_properties_limit();
|
|
} else {
|
|
disable_remove_hard_mode_ship_properties_limit();
|
|
}
|
|
if(IS_CONFIG_ENABLED(REMOVE_HARD_MODE_SHIP_TYPE_LIMIT)) {
|
|
enable_remove_hard_mode_ship_type_limit();
|
|
} else {
|
|
disable_remove_hard_mode_ship_type_limit();
|
|
}
|
|
if(IS_CONFIG_ENABLED(NO_BB_ANIMATION)) {
|
|
enable_no_bb_animation();
|
|
} else {
|
|
disable_no_bb_animation();
|
|
}
|
|
if(IS_CONFIG_ENABLED(NO_EMOTION_WARNING)) {
|
|
enable_no_emotion_warning();
|
|
} else {
|
|
disable_no_emotion_warning();
|
|
}
|
|
if(IS_CONFIG_ENABLED(OPSI_FAST_MOVE)) {
|
|
enable_opsi_fast_move();
|
|
} else {
|
|
disable_opsi_fast_move();
|
|
}
|
|
if(IS_CONFIG_ENABLED(GG_FACTOR)) {
|
|
update_gg_factor(config.gg_factor);
|
|
enable_gg_factor();
|
|
} else {
|
|
disable_gg_factor();
|
|
}
|
|
if(IS_CONFIG_ENABLED(GLOBAL_SPEEDUP)) {
|
|
update_global_speedup_rate(config.global_speedup_rate);
|
|
enable_global_speedup();
|
|
} else {
|
|
disable_global_speedup();
|
|
}
|
|
if(IS_CONFIG_ENABLED(EXERCISE_GOD_MOD)) {
|
|
enable_exercise_god_mode();
|
|
} else {
|
|
disable_exercise_god_mode();
|
|
}
|
|
if(IS_CONFIG_ENABLED(EXERCISE_MORE_POWER)) {
|
|
update_exercise_more_power_rate(config.exercise_more_power_rate / 100.0);
|
|
enable_exercise_more_power();
|
|
} else {
|
|
disable_exercise_more_power();
|
|
}
|
|
if(IS_CONFIG_ENABLED(FAST_WAVE)) {
|
|
enable_fast_wave();
|
|
} else {
|
|
disable_fast_wave();
|
|
}
|
|
if(IS_CONFIG_ENABLED(MONSTER_KILL_SELF)) {
|
|
enable_monster_kill_self();
|
|
} else {
|
|
disable_monster_kill_self();
|
|
}
|
|
if(IS_CONFIG_ENABLED(SKIP_BATTLE_CELEBRATE)) {
|
|
enable_skip_battle_celebrate();
|
|
} else {
|
|
disable_skip_battle_celebrate();
|
|
}
|
|
if(IS_CONFIG_ENABLED(BETTER_GLOBAL_SPEEDUP)) {
|
|
update_better_global_speedup_rate(config.better_global_speedup_rate);
|
|
enable_better_global_speedup();
|
|
} else {
|
|
disable_better_global_speedup();
|
|
}
|
|
if(IS_CONFIG_ENABLED(NO_DAMAGE)) {
|
|
enable_no_damage();
|
|
} else {
|
|
disable_no_damage();
|
|
}
|
|
}
|
|
|
|
void Cracker::load_cracker_with_pause() {
|
|
m_lua_state_pauser.do_when_paused([&]() {
|
|
SPDLOG_INFO("Load cracker with lua pause");
|
|
load_lua_resources();
|
|
hook_all_lua_functions();
|
|
load_real_lua_func();
|
|
});
|
|
}
|
|
|
|
void Cracker::load_cracker_without_pause() {
|
|
SPDLOG_INFO("Load cracker directly");
|
|
load_lua_resources();
|
|
hook_all_lua_functions();
|
|
load_real_lua_func();
|
|
}
|
|
|
|
void Cracker::load_real_lua_func() {
|
|
m_real_func.Chapter_IsAutoFight = m_state["Chapter"]["IsAutoFight"];
|
|
m_real_func.LevelStageView_tryAutoTrigger = m_state["LevelStageView"]["tryAutoTrigger"];
|
|
}
|
|
|
|
void Cracker::ensure_data_proxies() {
|
|
if (m_proxy_data_loaded) {
|
|
return;
|
|
}
|
|
|
|
SPDLOG_INFO("Load data proxies");
|
|
Lua::Table proxies = m_state["pg"]["proxyRegister"]["data"];
|
|
for (int i = 1; i <= proxies.size(); ++i) {
|
|
Lua::Table proxy = proxies[i];
|
|
std::string proxy_name = proxy["proxyName"];
|
|
if (proxy_name == "PlayerProxy") {
|
|
Lua::Table proxy_map = proxy["facade"]["model"]["proxyMap"];
|
|
m_data_proxy.player = proxy_map["PlayerProxy"];
|
|
m_data_proxy.dock = proxy_map["BayProxy"];
|
|
m_data_proxy.storage = proxy_map["BagProxy"];
|
|
} else if (proxy_name == "WorldProxy") {
|
|
m_data_proxy.world = proxy["facade"]["model"]["proxyMap"]["WorldProxy"];
|
|
}
|
|
}
|
|
m_proxy_data_loaded = true;
|
|
}
|
|
|
|
void Cracker::mover_stop(sol::this_state& L) {
|
|
if (m_mover.moving) {
|
|
if (m_mover.view.has_value()) {
|
|
auto& view_v = m_mover.view.value();
|
|
std::optional<Lua::Table> contextData = view_v["contextData"];
|
|
if (contextData.has_value()) {
|
|
auto& contextData_v = contextData.value();
|
|
std::optional<Lua::Table> chapterVO = contextData_v["chapterVO"];
|
|
if (chapterVO.has_value() && m_mover.path.has_value()) {
|
|
if (!m_mover.path.value().empty()) {
|
|
Lua::Table lastP = m_mover.path.value()[m_mover.path.value().size()];
|
|
std::optional<Lua::Table> fl = chapterVO.value()["fleet"]["line"];
|
|
if (fl.has_value()) {
|
|
auto& fl_v = fl.value();
|
|
int fl_row = fl_v["row"];
|
|
int fl_column = fl_v["column"];
|
|
int lastP_row = lastP["row"];
|
|
int lastP_column = lastP["column"];
|
|
|
|
if (fl_row != lastP_row || fl_column != lastP_column) {
|
|
fl_v["row"] = lastP_row;
|
|
fl_v["column"] = lastP_column;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_mover.currentStepSize = m_mover.stepSize;
|
|
m_mover.lastMoveStartP.reset();
|
|
m_mover.lastTargetIdx = 0;
|
|
m_mover.moving = false;
|
|
}
|
|
|
|
void Cracker::mover_go(sol::this_state& L, Lua::Table& view, Lua::Table& path) {
|
|
if (view.empty()) {
|
|
return;
|
|
}
|
|
m_mover.path = path;
|
|
m_mover.idx = 1;
|
|
m_mover.moving = true;
|
|
m_mover.view = view;
|
|
|
|
Lua::Table chapterVO = m_mover.view.value()["contextData"]["chapterVO"];
|
|
Lua::Table lastMoveStartP = m_state.create_table();
|
|
lastMoveStartP["row"] = chapterVO["fleet"]["line"]["row"];
|
|
lastMoveStartP["column"] = chapterVO["fleet"]["line"]["column"];
|
|
m_mover.lastMoveStartP = lastMoveStartP;
|
|
m_mover.currentStepSize = m_mover.stepSize;
|
|
m_mover.lastTargetIdx = 0;
|
|
|
|
mover_step(L);
|
|
}
|
|
|
|
void Cracker::mover_step(sol::this_state& L) {
|
|
std::optional<Lua::Table> chapterVO = m_mover.view.value()["contextData"]["chapterVO"];
|
|
if (!chapterVO.has_value()) {
|
|
mover_stop(L);
|
|
return;
|
|
}
|
|
Lua::Table fl = chapterVO.value()["fleet"]["line"];
|
|
|
|
int fl_row = fl["row"];
|
|
int fl_column = fl["column"];
|
|
|
|
if (m_mover.idx > 1 && m_mover.lastMoveStartP.has_value()) {
|
|
auto& lastMoveStartP_v = m_mover.lastMoveStartP.value();
|
|
int lastMoveStartP_row = lastMoveStartP_v["row"];
|
|
int lastMoveStartP_column = lastMoveStartP_v["column"];
|
|
|
|
if (fl_row == lastMoveStartP_row && fl_column == lastMoveStartP_column) {
|
|
int new_step = std::max(1, m_mover.currentStepSize - 1);
|
|
|
|
if (new_step < m_mover.currentStepSize) {
|
|
m_mover.currentStepSize = new_step;
|
|
m_mover.idx = m_mover.lastTargetIdx - (m_mover.currentStepSize - 1);
|
|
m_mover.idx = std::max(1, m_mover.idx);
|
|
} else if (new_step == 1) {
|
|
mover_stop(L);
|
|
return;
|
|
}
|
|
} else {
|
|
if (m_mover.currentStepSize < m_mover.stepSize) {
|
|
m_mover.currentStepSize = m_mover.stepSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!m_mover.moving || m_mover.idx > m_mover.path.value().size()) {
|
|
mover_stop(L);
|
|
return;
|
|
}
|
|
|
|
Lua::Table lastMoveStartP = m_state.create_table();
|
|
lastMoveStartP["row"] = fl_row;
|
|
lastMoveStartP["column"] = fl_column;
|
|
m_mover.lastMoveStartP = lastMoveStartP;
|
|
|
|
int targetIdx = std::min(m_mover.idx + m_mover.currentStepSize - 1, static_cast<int>(m_mover.path.value().size()));
|
|
Lua::Table p = m_mover.path.value()[targetIdx];
|
|
m_mover.lastTargetIdx = targetIdx;
|
|
|
|
int p_row = p["row"];
|
|
int p_column = p["column"];
|
|
|
|
Lua::Table emit_args = m_state.create_table();
|
|
int id = chapterVO.value()["fleet"]["id"];
|
|
emit_args["type"] = m_lua_res.ChapterConst_OpMove;
|
|
emit_args["id"] = id;
|
|
emit_args["arg1"] = p_row;
|
|
emit_args["arg2"] = p_column;
|
|
|
|
m_lua_res.LevelStageView_emit(L, m_mover.view.value(), m_lua_res.LevelMediator2_ON_OP, emit_args);
|
|
|
|
m_mover.idx = targetIdx + 1;
|
|
if (m_mover.idx <= m_mover.path.value().size()) {
|
|
Lua::Object tr = m_lua_res.Timer_New(L, [this](sol::this_state l, Lua::VariadicArgs args) {
|
|
mover_step(l);
|
|
}, m_mover.interval, 1);
|
|
m_lua_res.Timer_Start(L, tr);
|
|
} else {
|
|
mover_stop(L);
|
|
}
|
|
}
|
|
|
|
bool Cracker::my_ChapterConst_IsBossCell(sol::this_state& L, Lua::Table& cell) {
|
|
std::optional<Lua::Object> result = m_lua_res.ChapterConst_IsBossCell(L, cell);
|
|
if (!result.has_value()) {
|
|
return false;
|
|
}
|
|
|
|
auto& result_v = result.value();
|
|
if (result_v.get_type() == sol::type::nil) {
|
|
return false;
|
|
}
|
|
return result_v.as<bool>();
|
|
}
|
|
|
|
int Cracker::CntNonBoss(sol::this_state& L, Lua::Table& chap) {
|
|
int n = 0;
|
|
|
|
std::optional<Lua::Table> chap_cells = chap["cells"];
|
|
if (chap_cells.has_value()) {
|
|
chap_cells->for_each([&](sol::object key, sol::object value) {
|
|
if (!value.is<Lua::Table>()) {
|
|
return;
|
|
}
|
|
Lua::Table cell = value.as<Lua::Table>();
|
|
std::optional<Lua::Object> cell_flag = cell["flag"];
|
|
if(cell_flag.has_value()) {
|
|
if (!cell_flag->is<int>()) {
|
|
return;
|
|
}
|
|
int cell_attachment = cell["attachment"];
|
|
bool is_enemy_attach = m_lua_res.ChapterConst_IsEnemyAttach(L, cell_attachment);
|
|
bool is_boss_cell = my_ChapterConst_IsBossCell(L, cell);
|
|
if((cell_flag->as<int>() == m_lua_res.ChapterConst_CellFlagActive) && (is_enemy_attach) && (!is_boss_cell)) {
|
|
n += 1;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
std::optional<Lua::Table> chap_champions = chap["champions"];
|
|
if(chap_champions.has_value()) {
|
|
|
|
chap_champions->for_each([&](sol::object key, sol::object value) {
|
|
if(!value.is<Lua::Table>()) {
|
|
return;
|
|
}
|
|
|
|
Lua::Table cp = value.as<Lua::Table>();
|
|
std::optional<Lua::Object> cp_flag = cp["flag"];
|
|
|
|
if(cp_flag.has_value()) {
|
|
if(!cp_flag->is<int>()) {
|
|
return;
|
|
}
|
|
bool is_boss_cell = my_ChapterConst_IsBossCell(L, cp);
|
|
if((cp_flag->as<int>() != m_lua_res.ChapterConst_CellFlagDisabled) && (!is_boss_cell)) {
|
|
n += 1;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
std::optional<Cracker::Cell> Cracker::NearestEnemy(sol::this_state& L, Lua::Table& chap, bool farming) {
|
|
bool hasNoneBoss = CntNonBoss(L, chap) > 0;
|
|
Lua::Table fl = chap["fleet"]["line"];
|
|
std::optional<Cracker::Cell> best;
|
|
std::optional<int> bestDist;
|
|
|
|
auto CheckCell = [&] (Lua::Table& cell) {
|
|
if (farming && hasNoneBoss) {
|
|
if (bool is_boss_cell = m_lua_res.ChapterConst_IsBossCell(L, cell)) {
|
|
return;
|
|
}
|
|
}
|
|
int cell_row = cell["row"];
|
|
int cell_column = cell["column"];
|
|
int fl_row = fl["row"];
|
|
int fl_column = fl["column"];
|
|
|
|
if (cell_row == fl_row && cell_column == fl_column) {
|
|
return;
|
|
}
|
|
|
|
int d = std::abs(cell_row - fl_row) + std::abs(cell_column - fl_column);
|
|
|
|
if (!bestDist.has_value()) {
|
|
bestDist.emplace(d);
|
|
best = Cracker::Cell{cell_row, cell_column};
|
|
} else {
|
|
if (d < bestDist.value()) {
|
|
bestDist.emplace(d);
|
|
best = Cracker::Cell{cell_row, cell_column};
|
|
}
|
|
}
|
|
|
|
// SPDLOG_INFO("Check [{}, {}], fleet=[{}, {}], best = [{}, {}], bestDist = {}", cell_row, cell_column, fl_row, fl_column, best->row, best->column, bestDist.value());
|
|
};
|
|
|
|
std::optional<Lua::Table> chap_cells = chap["cells"];
|
|
if (chap_cells.has_value()) {
|
|
chap_cells->for_each([&](sol::object key, sol::object value) {
|
|
if (!value.is<Lua::Table>()) {
|
|
return;
|
|
}
|
|
Lua::Table cell = value.as<Lua::Table>();
|
|
std::optional<Lua::Object> cell_flag = cell["flag"];
|
|
if(cell_flag.has_value()) {
|
|
if (!cell_flag->is<int>()) {
|
|
return;
|
|
}
|
|
int cell_attachment = cell["attachment"];
|
|
bool is_enemy_attach = m_lua_res.ChapterConst_IsEnemyAttach(L, cell_attachment);
|
|
if((cell_flag->as<int>() == m_lua_res.ChapterConst_CellFlagActive) && (is_enemy_attach)) {
|
|
CheckCell(cell);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
std::optional<Lua::Table> chap_champions = chap["champions"];
|
|
if(chap_champions.has_value()) {
|
|
chap_champions->for_each([&](sol::object key, sol::object value) {
|
|
if(!value.is<Lua::Table>()) {
|
|
return;
|
|
}
|
|
|
|
Lua::Table cp = value.as<Lua::Table>();
|
|
std::optional<Lua::Object> cp_flag = cp["flag"];
|
|
|
|
if(cp_flag.has_value()) {
|
|
if(!cp_flag->is<int>()) {
|
|
return;
|
|
}
|
|
if(cp_flag->as<int>() != m_lua_res.ChapterConst_CellFlagDisabled) {
|
|
CheckCell(cp);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
#define FALLBACK_TO_ORIGINAL() \
|
|
m_original.LevelStageView_TryAutoFight(L, args); \
|
|
return;
|
|
|
|
void Cracker::my_LevelStageView_TryAutoFight(sol::this_state& L, Lua::VariadicArgs& args) {
|
|
Lua::Table self = args[0];
|
|
std::optional<Lua::Table> chap = self["contextData"]["chapterVO"];
|
|
|
|
if (!chap.has_value()) {
|
|
FALLBACK_TO_ORIGINAL();
|
|
}
|
|
|
|
bool is_auto_fight = m_real_func.Chapter_IsAutoFight(L, chap.value());
|
|
if (!is_auto_fight) {
|
|
FALLBACK_TO_ORIGINAL();
|
|
}
|
|
|
|
auto& chap_v = chap.value();
|
|
|
|
bool is_any_interactive = m_lua_res.Chapter_checkAnyInteractive(L, chap_v);
|
|
if (is_any_interactive) {
|
|
m_real_func.LevelStageView_tryAutoTrigger(L, self, sol::nil, true);
|
|
return;
|
|
}
|
|
|
|
int chap_progress = chap_v["progress"];
|
|
if (chap_progress >= 100) {
|
|
FALLBACK_TO_ORIGINAL();
|
|
}
|
|
|
|
if (m_mover.moving) {
|
|
return;
|
|
}
|
|
|
|
auto enemy = NearestEnemy(L, chap_v, true);
|
|
if (!enemy.has_value()) {
|
|
return;
|
|
}
|
|
auto& enemy_v = enemy.value();
|
|
|
|
std::optional<Lua::Table> fleet = m_lua_res.Chapter_GetFleetOfDuty(L, chap_v, true);
|
|
if (!fleet.has_value()) {
|
|
return;
|
|
}
|
|
auto& fleet_v = fleet.value();
|
|
int fleet_row = fleet_v["line"]["row"];
|
|
int fleet_column = fleet_v["line"]["column"];
|
|
|
|
if (fleet_row == enemy_v.row && fleet_column == enemy_v.column) {
|
|
m_real_func.LevelStageView_tryAutoTrigger(L, self, sol::nil, true);
|
|
return;
|
|
}
|
|
|
|
Lua::Table enemy_cell = m_state.create_table();
|
|
enemy_cell["row"] = enemy_v.row;
|
|
enemy_cell["column"] = enemy_v.column;
|
|
|
|
Lua::Table fleet_line = fleet_v["line"];
|
|
|
|
std::tuple<Lua::Object, Lua::Table> result = m_lua_res.Chapter_findPath(L, chap_v, m_lua_res.ChapterConst_SubjectPlayer, fleet_line, enemy_cell);
|
|
auto& path = std::get<1>(result);
|
|
if(path.empty()) {
|
|
return;
|
|
}
|
|
|
|
mover_go(L, self, path);
|
|
}
|
|
|
|
#define MODIFY_PROPERTY(name) \
|
|
if (new_properties.name >= 0) { \
|
|
properties[#name] = new_properties.name; \
|
|
}
|
|
|
|
void Cracker::modify_ship_properties(Lua::Table& properties, const ShipProperties& new_properties) {
|
|
MODIFY_PROPERTY(armor)
|
|
MODIFY_PROPERTY(speed)
|
|
MODIFY_PROPERTY(antiaircraft)
|
|
MODIFY_PROPERTY(oxy_recovery_bench)
|
|
MODIFY_PROPERTY(torpedo)
|
|
MODIFY_PROPERTY(hit)
|
|
MODIFY_PROPERTY(sonarRange)
|
|
MODIFY_PROPERTY(attack_duration)
|
|
MODIFY_PROPERTY(raid_distance)
|
|
MODIFY_PROPERTY(oxy_recovery_surface)
|
|
MODIFY_PROPERTY(oxy_recovery)
|
|
MODIFY_PROPERTY(dodge)
|
|
MODIFY_PROPERTY(luck)
|
|
MODIFY_PROPERTY(reload)
|
|
MODIFY_PROPERTY(oxy_cost)
|
|
MODIFY_PROPERTY(durability)
|
|
MODIFY_PROPERTY(air)
|
|
MODIFY_PROPERTY(oxy_max)
|
|
MODIFY_PROPERTY(cannon)
|
|
MODIFY_PROPERTY(antisub)
|
|
}
|
|
|
|
void Cracker::clear_hard_mode_ship_properties_limit(Lua::Table& t) {
|
|
for (int i = 1, n = t.size(); i <= n; ++i) {
|
|
sol::table fleet = t[i];
|
|
for (int j = 1, m = fleet.size(); j <= m; ++j) {
|
|
sol::table team = fleet[j];
|
|
for (int k = 1, l = team.size(); k <= l; ++k) {
|
|
team[k] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
}
|