From 3b24a7e47859ed7e21f26fba6ca2bcc752dbc726 Mon Sep 17 00:00:00 2001 From: Knaapchen Date: Thu, 20 Oct 2022 14:53:07 +0200 Subject: [PATCH] Pre Halloween patch --- flyff-api/src/Mover.h | 114 ++++++++++++++++++++++++++++++++----- flyff-api/src/Neuz.cpp | 8 +-- flyff-api/src/core.h | 6 +- flyff-client/src/client.c | 8 +-- fugg-client/src/client.cpp | 78 +++++++++++++++++-------- 5 files changed, 167 insertions(+), 47 deletions(-) diff --git a/flyff-api/src/Mover.h b/flyff-api/src/Mover.h index 99a4245..cb9ed0f 100644 --- a/flyff-api/src/Mover.h +++ b/flyff-api/src/Mover.h @@ -12,8 +12,22 @@ #include "math.h" #include "item.h" + namespace flyff { +namespace raw { + extern "C" { + // w2c_f410: CMover::GetHitPoint(PlayerObject* mover); + extern u32 w2c_f410(u32); + // w2c_f2454: CCooltimeMgr::CanUse(uint64_t* timers, ItemProperty* prop); + extern u32 w2c_f2454(u32, u32); + } +}; + struct __attribute__((packed)) Mover { + static constexpr uint32_t MAX_PARAM = 82; + + using Parameter = unsigned long; + using ObjectStateFlags = Object::StateFlags; using ObjectState = Object::State; @@ -22,6 +36,9 @@ struct __attribute__((packed)) Mover { DEFINE_MEMBER(52, u32, get_level); DEFINE_MEMBER(56, u32, get_gender); + DEFINE_MEMBER(144, u32, get_max_origin_hp); + DEFINE_MEMBER(148, u32, get_max_origin_mp); + const MinimumSize<220> __size; }; }; @@ -40,9 +57,13 @@ struct __attribute__((packed)) Mover { DEFINE_MEMBER(216, bool, is_despawned); DEFINE_MEMBER(352, MoverID, object_id); + DEFINE_MEMBER(920, Parameter, adjustParam[MAX_PARAM]); + DEFINE_MEMBER(1248, Parameter, changeParam[MAX_PARAM]); + DEFINE_MEMBER(2020, const String, name); DEFINE_MEMBER(1628, Vector3, move_target); + DEFINE_MEMBER(1688, unsigned long long, last_combat); DEFINE_MEMBER(1728, MoverID, move_toward_target); DEFINE_MEMBER(1736, MoverID, last_attacked_target); @@ -54,8 +75,11 @@ struct __attribute__((packed)) Mover { DEFINE_MEMBER(1768, MoverID, current_attack_target); DEFINE_MEMBER(1776, MoverID, platform_standing_on); + DEFINE_MEMBER(1816, int, adj_param); DEFINE_MEMBER(1820, uint32_t, server_tick); + DEFINE_MEMBER(1840, int, hitpoints); + DEFINE_MEMBER(1792, int, current_animation); DEFINE_MEMBER(204, ObjectType, type); @@ -74,9 +98,82 @@ struct __attribute__((packed)) Mover { DEFINE_MEMBER(860, Vector, inventory); + + DEFINE_MEMBER(3324, uint64_t, last_food_time); + DEFINE_MEMBER(3348, uint64_t, last_refresher_time); + DEFINE_MEMBER(3356, uint64_t, last_vitaldrink_time); + const MinimumSize<4096> __size; }; + bool can_use_item(const Pointer& property) { + return raw::w2c_f2454(kMemory.to_inside(&last_food_time), static_cast(property)); + } + + bool is_in_combat() const { + const unsigned long long& now = fugg::module_ref(0x00032a18); + // 10 seconds + return now - last_combat < 10000000; + } + + Parameter get_param(uint32_t index, Parameter base) const { + Parameter changeParam = get_change_param(index); + if(changeParam != 0x7FFFFFFF) + return changeParam; + + Parameter adjustParam = get_adjust_param(index); + if(adjustParam) + return base + adjustParam; + else + return base; + } + + Parameter get_adjust_param(Parameter index) const { + // Find these values in CMover::Init + return adjustParam[index] ^ adj_param ^ 0x0554e725 + index * 0x41c64e6d; + } + + Parameter get_change_param(Parameter index) const { + return changeParam[index] ^ adj_param ^ index * 0x41c64e6d + 0xb5a52d1a; + } + + u32 get_hp() const { + return raw::w2c_f410(kMemory.to_inside(this)); + } + + u32 get_max_hp() const { + static constexpr Parameter DST_HP_MAX = 0x2c; + static constexpr Parameter DST_HP_MAX_RATE = 0x35; + + float factor = 1.0f; + int result = get_param(DST_HP_MAX, get_max_origin_hp()); + int percent = get_param(DST_HP_MAX_RATE, 0); + + factor += (float)percent / (float)100; + result = (int)(result * factor); + + return result; + } + + u32 get_hp_percent(int percent = 100) const { + int max = get_max_hp(); + if(max == 0) return 0; + + return get_hp() * percent / max; + } + + u32 get_max_origin_hp() const { + using Fn = FunctionPointer; + const auto& fn = fugg::function_ref(vtable->get_max_origin_hp); + + return fn(kMemory.to_inside(this), 0, 0); + } + + + // int get_max_hp() const { + // return raw::w2c_f410(kMemory.to_inside(this)); + // } + uint32_t get_state() const { return object_state; } @@ -158,14 +255,11 @@ struct __attribute__((packed)) Mover { return (object_state & ObjectState::TurnAll) != 0; } - // int32_t get_level() { - // // The function itself works but I fear it returns wrong results. - // // Npc = 1 - // // Players = 0 - // const auto& fn = fugg::function_ref>>(vtable->get_level); + u32 get_level() { + const auto& fn = fugg::function_ref>(vtable->get_level); - // return fn(Pointer(this)); - // } + return fn(kMemory.to_inside(this)); + } // int32_t get_gender() { // // The function itself works but I fear it returns wrong results. @@ -176,12 +270,6 @@ struct __attribute__((packed)) Mover { // return fn(Pointer(this)); // } - - // bool prevents_pickup_emote() const { - // DEFINE_MEMBER(1806, uint16_t, pickup_flags); - // // Returns true if in attack animation - // return (pickup_flags & 0x8ff) != 0; - // } }; struct MoverMap { diff --git a/flyff-api/src/Neuz.cpp b/flyff-api/src/Neuz.cpp index 39bb49f..62cf54d 100644 --- a/flyff-api/src/Neuz.cpp +++ b/flyff-api/src/Neuz.cpp @@ -102,7 +102,7 @@ void Neuz::show_message(const std::string& message, auto color_ = std::make_unique(color); raw::show_message( - static_cast(messages_ui), + static_cast(messages_ui), fugg::RuntimePointer(message_.get()).as_raw(), fugg::RuntimePointer(color_.get()).as_raw()); } @@ -116,15 +116,15 @@ void Neuz::show_announcement(const std::string& message, auto color_ = std::make_unique(color); raw::show_announcement( - static_cast(announcements_ui), + static_cast(announcements_ui), fugg::RuntimePointer(message_.get()).as_raw(), fugg::RuntimePointer(color_.get()).as_raw()); } bool Neuz::is_valid_attack(const Pointer& attacker, const Pointer& defender) const { - auto result = raw::w2c_f514(static_cast(attacker), - static_cast(defender)); + auto result = raw::w2c_f514(static_cast(attacker), + static_cast(defender)); return result != 0; } diff --git a/flyff-api/src/core.h b/flyff-api/src/core.h index 18d2e2d..c45db98 100644 --- a/flyff-api/src/core.h +++ b/flyff-api/src/core.h @@ -37,6 +37,10 @@ class Memory { uintptr_t to_inside(const uintptr_t offset) { return offset != NULL ? offset - start() : NULL; } + + intptr_t to_inside(const void* offset) { + return to_inside(reinterpret_cast(offset)); + } uintptr_t to_outside(const uintptr_t offset) { return offset != NULL ? reinterpret_cast(&(*memory)->data[offset]) : NULL; @@ -95,7 +99,7 @@ class __attribute__((packed)) Pointer { return as_outside(); } - explicit operator uintptr_t() const { + explicit operator u32() const { return offset; } diff --git a/flyff-client/src/client.c b/flyff-client/src/client.c index 7dc45d4..5b273a3 100644 --- a/flyff-client/src/client.c +++ b/flyff-client/src/client.c @@ -651,7 +651,7 @@ static u32 w2c_f406(u32); static u32 w2c_f407(u32); static void w2c_f408(u32); static u32 w2c_f409(u32); -static u32 w2c_f410(u32); +u32 w2c_f410(u32); static void w2c_f411(u32, u32); static u32 w2c_f412(u32); static u32 w2c_f413(u32, u32); @@ -2695,7 +2695,7 @@ static void w2c_f2450(u32, u32, u32, u32); static void w2c_f2451(u32, u32, u32); static u32 w2c_f2452(u32); static u32 w2c_f2453(u32); -static u32 w2c_f2454(u32, u32); +u32 w2c_f2454(u32, u32); static u32 w2c_f2455(u32); static u32 w2c_f2456(u32); static void w2c_f2457(void); @@ -98640,7 +98640,7 @@ static u32 w2c_f409(u32 w2c_p0) { return w2c_i0; } -static u32 w2c_f410(u32 w2c_p0) { +u32 w2c_f410(u32 w2c_p0) { u32 w2c_l1 = 0, w2c_l2 = 0, w2c_l3 = 0; f32 w2c_l4 = 0; FUNC_PROLOGUE; @@ -1095840,7 +1095840,7 @@ static u32 w2c_f2453(u32 w2c_p0) { return w2c_i0; } -static u32 w2c_f2454(u32 w2c_p0, u32 w2c_p1) { +u32 w2c_f2454(u32 w2c_p0, u32 w2c_p1) { u32 w2c_l2 = 0, w2c_l3 = 0; u64 w2c_l4 = 0; FUNC_PROLOGUE; diff --git a/fugg-client/src/client.cpp b/fugg-client/src/client.cpp index 6d5bb8e..dd28b2a 100644 --- a/fugg-client/src/client.cpp +++ b/fugg-client/src/client.cpp @@ -9,10 +9,8 @@ namespace fugg { } -constexpr const uint32_t hash_to_id(const uint32_t hashed) { - constexpr uint32_t header_hash = 0x644ab400; - - return hashed ^ header_hash; +constexpr const uint32_t hash_to_id(const uint32_t hashed) { + return hashed ^ flyff::PACKET_HEADER_HASH; } template @@ -208,7 +206,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent* event, void* u if(mover->type == ObjectType::Mover) { // int level = mover->get_level(); - std::cout << neuz.get_text(mover->name) << ": " + std::cout << neuz.get_text(mover->name) << " get_level() << ">): " << (mover->is_dead() ? "Dead" : "Not dead") << ", " << (mover->is_fly() ? "Flying" : "Not flying") << ", " << (mover->is_jumping() ? "Jumping" : "Not jumping") << ", " @@ -358,10 +356,10 @@ void interact(const flyff::MoverID& id) { if(!neuz.player) return; - // neuz.player->selected_target = id; + neuz.player->selected_target = id; set_target(id); - // neuz.player->move_toward_target = id; + neuz.player->move_toward_target = id; interact_target(1); } @@ -374,6 +372,16 @@ void bot_tick() { if(!neuz.player) return; + // std::cout << "Max Max HP: " + // << neuz.player->get_max_hp() + // << ", Adjust HP:" + // << neuz.player->get_adjust_param(0x2c) + // << ", Player level: " + // << neuz.player->get_level() + // << std::endl; + + // printf("%#010x\n", neuz.player->get_state()); + if(is_running) { if(neuz.player->is_dead()) { neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00}); @@ -389,10 +397,31 @@ void bot_tick() { if(neuz.player->get_move_state() == 1 && !neuz.player->is_attacking()) { - if(current_pickup_item != nullptr && !current_pickup_item->is_despawned && neuz.player->move_toward_target == 0) { + + if(neuz.player->get_hp_percent() < 75) { + neuz.show_message("Fooding because HP is under 75%"); + + const auto& player = neuz.player; + + auto items = player->inventory.begin(); + auto length = ((uintptr_t)player->inventory.end() - (uintptr_t)player->inventory.begin()) / 0x60; + + for(auto i = 0; i < length; i++) { + if(items[i].index != -1 && + items[i].property && + items[i].property->is_food_item() && + player->can_use_item(items[i].property)) { + neuz.show_message(neuz.get_text(items[i].property->name)); + + use_item_in_inventory(i); + + break; + } + } + } else if(current_pickup_item != nullptr && !current_pickup_item->is_despawned && neuz.player->move_toward_target == 0) { // Pickup interact(current_pickup_item->object_id); - } else if(current_target && !current_target->is_dead() && neuz.player->attack_target == 0) { + } else if(current_target && !current_target->is_dead() && neuz.player->attack_target == 0 && neuz.player->move_toward_target == 0) { // Attack interact(current_target->object_id); // neuz.player->attack_target = current_target->object_id; @@ -410,24 +439,23 @@ void bot_tick() { interact(current_pickup_item->object_id); - neuz.show_message(str); - return; - } - - current_target = attack_next_target(start_position); - - if(current_target) { - std::string str = "Attacking "; - str.append(current_target->name); - - std::cout << str << std::endl; - - interact(current_target->object_id); - neuz.player->attack_target = current_target->object_id; - neuz.show_message(str); } else { - neuz.show_message("Unable to find target."); + current_target = attack_next_target(start_position); + + if(current_target) { + std::string str = "Attacking "; + str.append(current_target->name); + + std::cout << str << std::endl; + + interact(current_target->object_id); + neuz.player->attack_target = current_target->object_id; + + neuz.show_message(str); + } else { + neuz.show_message("Unable to find target."); + } } } }