From 4a5b4790d441fac56d47bf1e08465514006ae7da Mon Sep 17 00:00:00 2001 From: Knaapchen Date: Thu, 27 Oct 2022 19:40:41 +0200 Subject: [PATCH] Lots of refactoring --- flyff-api/CMakeLists.txt | 2 +- flyff-api/src/core.h | 4 + flyff-api/src/object/mover/Mover.cpp | 4 +- flyff-api/src/object/mover/Mover.h | 52 +-- flyff-api/src/object/mover/ParamID.h | 21 + flyff-client/src/client.c | 15 + fugg-client/CMakeLists.txt | 2 +- fugg-client/src/Action.h | 25 -- fugg-client/src/Bot.cpp | 18 - fugg-client/src/Bot.h | 28 -- fugg-client/src/Client.cpp | 560 ++++++++++++++++----------- fugg-client/src/Client.h | 10 +- fugg-client/src/behaviour/Action.h | 57 +++ fugg-client/src/behaviour/Script.h | 19 + 14 files changed, 483 insertions(+), 334 deletions(-) create mode 100644 flyff-api/src/object/mover/ParamID.h delete mode 100644 fugg-client/src/Action.h delete mode 100644 fugg-client/src/Bot.cpp delete mode 100644 fugg-client/src/Bot.h create mode 100644 fugg-client/src/behaviour/Action.h create mode 100644 fugg-client/src/behaviour/Script.h diff --git a/flyff-api/CMakeLists.txt b/flyff-api/CMakeLists.txt index 722820c..73a870e 100644 --- a/flyff-api/CMakeLists.txt +++ b/flyff-api/CMakeLists.txt @@ -8,7 +8,7 @@ add_library( "include/flyff.h" src/core.h src/skill/SkillProperty.h - src/object/ObjectProperty.h src/item/ItemKind2.h src/item/ItemKind3.h src/item/Part.h src/item/InventoryItem.h src/object/mover/JobProperty.h) + src/object/ObjectProperty.h src/item/ItemKind2.h src/item/ItemKind3.h src/item/Part.h src/item/InventoryItem.h src/object/mover/JobProperty.h src/object/mover/ParamID.h) target_include_directories(flyff-api PUBLIC "include") target_link_libraries(flyff-api PUBLIC flyff-client fugg-api) \ No newline at end of file diff --git a/flyff-api/src/core.h b/flyff-api/src/core.h index 7754ba3..ebcfa68 100644 --- a/flyff-api/src/core.h +++ b/flyff-api/src/core.h @@ -188,6 +188,10 @@ namespace flyff { T *end() const { return static_cast(end_); } + + size_t size() const { + return static_cast(end_ - begin_); + } }; static_assert(sizeof(Vector) == sizeof(std::vector), diff --git a/flyff-api/src/object/mover/Mover.cpp b/flyff-api/src/object/mover/Mover.cpp index d97d5c8..5e6326b 100644 --- a/flyff-api/src/object/mover/Mover.cpp +++ b/flyff-api/src/object/mover/Mover.cpp @@ -21,9 +21,9 @@ namespace flyff { return 0; } - bool Mover::is_in_combat() const { + bool Mover::is_in_combat(uint32_t millis) const { const auto &neuz = flyff::Neuz::instance(); // 10 seconds - return neuz.current_time - last_combat < 10000000; + return neuz.current_time - last_combat < (millis * 1000); } }; // namespace flyff \ No newline at end of file diff --git a/flyff-api/src/object/mover/Mover.h b/flyff-api/src/object/mover/Mover.h index 84bb83f..59a53f6 100644 --- a/flyff-api/src/object/mover/Mover.h +++ b/flyff-api/src/object/mover/Mover.h @@ -20,6 +20,7 @@ #include "../../item/InventoryItem.h" #include "../../item/Part.h" #include "JobProperty.h" +#include "ParamID.h" namespace flyff { namespace raw { @@ -36,9 +37,6 @@ namespace flyff { using Parameter = unsigned long; - static constexpr Parameter DST_HP_MAX = 0x2c; - static constexpr Parameter DST_HP_MAX_RATE = 0x35; - using ObjectStateFlags = Object::StateFlags; using ObjectState = Object::State; @@ -98,7 +96,7 @@ namespace flyff { return fn(kMemory.to_inside(this)); } - int get_id() const { + uint32_t get_id() const { using Fn = FunctionPointer; const auto &fn = fugg::function_ref(vtable->get_id); @@ -113,14 +111,15 @@ namespace flyff { DEFINE_MEMBER(0x18, Matrix4, world_matrix); - DEFINE_MEMBER(152, Vector3, position); - DEFINE_MEMBER(164, Vector3, rotation); + DEFINE_MEMBER(152, const Vector3, position); + DEFINE_MEMBER(164, const Vector3, rotation); DEFINE_MEMBER(188, const Pointer, property); - DEFINE_MEMBER(212, int, property_id); - DEFINE_MEMBER(216, bool, is_despawned); - DEFINE_MEMBER(352, MoverID, object_id); + DEFINE_MEMBER(212, const int, property_id); + DEFINE_MEMBER(216, const bool, is_despawned); + + DEFINE_MEMBER(352, const MoverID, object_id); DEFINE_MEMBER(920, Parameter, adjusted_parameters[MAX_PARAM]); DEFINE_MEMBER(1248, Parameter, changed_parameters[MAX_PARAM]); @@ -129,11 +128,15 @@ namespace flyff { DEFINE_MEMBER(2020, const String, name); + DEFINE_MEMBER(1616, const Vector, enemies); DEFINE_MEMBER(1628, Vector3, move_target); + + DEFINE_MEMBER(1652, Vector3, delta_velocity); + DEFINE_MEMBER(1688, unsigned long long, last_combat); DEFINE_MEMBER(1728, MoverID, move_toward_target); - DEFINE_MEMBER(1736, MoverID, last_attacked_target); + DEFINE_MEMBER(1736, MoverID, last_hit_mover); DEFINE_MEMBER(1744, MoverID, selected_target); // The id of the target that it hit last. DEFINE_MEMBER(1752, MoverID, attack_target); @@ -153,8 +156,6 @@ namespace flyff { DEFINE_MEMBER(204, const ObjectType, type); - DEFINE_MEMBER(216, uint32_t, existence_check); - DEFINE_MEMBER(1804, uint32_t, object_state); DEFINE_MEMBER(1808, uint32_t, object_state_flags); @@ -169,9 +170,9 @@ namespace flyff { DEFINE_MEMBER(2432, const flyff::Pointer, job_property); - DEFINE_MEMBER(3224, Timestamp, last_food_time); - DEFINE_MEMBER(3248, Timestamp, last_refresher_time); - DEFINE_MEMBER(3256, Timestamp, last_vitaldrink_time); + DEFINE_MEMBER(3224, const Timestamp, last_food_time); + DEFINE_MEMBER(3248, const Timestamp, last_refresher_time); + DEFINE_MEMBER(3256, const Timestamp, last_vitaldrink_time); DEFINE_MEMBER(3424, Vector, skills); @@ -199,9 +200,9 @@ namespace flyff { return max_inventory_slots - locked_inventory_slots; } - bool is_in_combat() const; + bool is_in_combat(uint32_t millis = 10000) const; - Parameter get_param(uint32_t index, Parameter base) const { + uint32_t get_param(ParamID index, uint32_t base) const { Parameter changeParam = get_change_param(index); if (changeParam != 0x7FFFFFFF) return changeParam; @@ -213,13 +214,16 @@ namespace flyff { return base; } - Parameter get_adjust_param(Parameter index) const { + Parameter get_adjust_param(ParamID index) const { + auto id = static_cast(index); // Find these values in CMover::Init - return adjusted_parameters[index] ^ adj_param ^ 0x0554e725 + index * 0x41c64e6d; + return adjusted_parameters[id] ^ adj_param ^ 0x0554e725 + id * 0x41c64e6d; } - Parameter get_change_param(Parameter index) const { - return changed_parameters[index] ^ adj_param ^ index * 0x41c64e6d + 0xb5a52d1a; + Parameter get_change_param(ParamID index) const { + auto id = static_cast(index); + + return changed_parameters[id] ^ adj_param ^ id * 0x41c64e6d + 0xb5a52d1a; } u32 get_hp() const { @@ -236,8 +240,8 @@ namespace flyff { uint32_t get_max_hp() const { float factor = 1.0f; - int result = get_param(DST_HP_MAX, get_max_origin_hp()); - int percent = get_param(DST_HP_MAX_RATE, 0); + auto result = get_param(ParamID::MaxHitPoint, get_max_origin_hp()); + auto percent = get_param(ParamID::MaxHitPointScaling, 0); factor += (float) percent / (float) 100; result = static_cast(result) * factor; @@ -246,7 +250,7 @@ namespace flyff { } uint32_t get_hp_percent(int percent = 100) const { - int max = get_max_hp(); + auto max = get_max_hp(); if (max == 0) return 0; return get_hp() * percent / max; diff --git a/flyff-api/src/object/mover/ParamID.h b/flyff-api/src/object/mover/ParamID.h new file mode 100644 index 0000000..7ebfafc --- /dev/null +++ b/flyff-api/src/object/mover/ParamID.h @@ -0,0 +1,21 @@ +// +// Created by main on 25-10-22. +// + +#ifndef FUGG_PARAMID_H +#define FUGG_PARAMID_H + +#include + +namespace flyff { + enum class ParamID : uint32_t { + // DST_HP_MAX + MaxHitPoint = 44, + // DST_HP_MAX_RATE + MaxHitPointScaling = 53, + }; + +} + + +#endif //FUGG_PARAMID_H diff --git a/flyff-client/src/client.c b/flyff-client/src/client.c index df50119..943fbd3 100644 --- a/flyff-client/src/client.c +++ b/flyff-client/src/client.c @@ -1051403,9 +1051403,24 @@ void w2c_f2316(u32 w2c_p0) { w2c_i0 = w2c_p0; w2c_i0 = i32_load((&w2c_memory), (u64)(w2c_i0) + 4u); w2c_l4 = w2c_i0; + + const uintptr_t end = w2c_l4; + w2c_i1 = w2c_p0; w2c_i1 = i32_load((&w2c_memory), (u64)(w2c_i1)); w2c_l2 = w2c_i1; + + const uintptr_t begin = w2c_l2; + + const size_t length = end - begin; + const unsigned char* data = &(&w2c_memory)->data[begin]; + + printf("Finalizing packet of length %zd: ", length); + for(int i = 0; i < length; i++) { + printf("%02X ", data[i]); + } + printf("\n"); + w2c_i0 -= w2c_i1; w2c_l7 = w2c_i0; w2c_i0 = 9u; diff --git a/fugg-client/CMakeLists.txt b/fugg-client/CMakeLists.txt index c3a49a9..8dab622 100644 --- a/fugg-client/CMakeLists.txt +++ b/fugg-client/CMakeLists.txt @@ -9,7 +9,7 @@ add_executable( "src/export/embind.cpp" "src/export/env.cpp" "src/export/platform.cpp" - src/Bot.cpp src/Bot.h src/Action.h src/Packet.h) + src/behaviour/Action.h src/Packet.h src/behaviour/Script.h) # Flyff is based on c++14 add_definitions(-std=c++14 -Os) diff --git a/fugg-client/src/Action.h b/fugg-client/src/Action.h deleted file mode 100644 index 0d274c4..0000000 --- a/fugg-client/src/Action.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Created by main on 21-10-22. -// - -#ifndef FUGG_ACTION_H -#define FUGG_ACTION_H - -#include "Bot.h" - -namespace fugg { - class Action { - - public: - enum class State : unsigned char { - Running, - Failed, - Succeeded - }; - - virtual State evaluate(Bot &bot) = 0; - }; -}; - - -#endif //FUGG_ACTION_H diff --git a/fugg-client/src/Bot.cpp b/fugg-client/src/Bot.cpp deleted file mode 100644 index e144a58..0000000 --- a/fugg-client/src/Bot.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by main on 21-10-22. -// - -#include "Bot.h" - -namespace fugg { - Bot &Bot::instance() { - // Constructor will be called. - static Bot instance; - // Whole module is initialised now. - return instance; - } - - void Bot::tick() { - - } -}; diff --git a/fugg-client/src/Bot.h b/fugg-client/src/Bot.h deleted file mode 100644 index e2f4486..0000000 --- a/fugg-client/src/Bot.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by main on 21-10-22. -// - -#ifndef FUGG_BOT_H -#define FUGG_BOT_H - -#include - -namespace fugg { - class Bot { - Bot(); - - flyff::Neuz &neuz; - - public: - static Bot &instance(); - - Bot(Bot const &) = delete; - - void operator=(Bot const &) = delete; - - void tick(); - }; -}; - - -#endif //FUGG_BOT_H diff --git a/fugg-client/src/Client.cpp b/fugg-client/src/Client.cpp index fc6021a..54be6cf 100644 --- a/fugg-client/src/Client.cpp +++ b/fugg-client/src/Client.cpp @@ -115,20 +115,24 @@ namespace fugg { send_packet(motion_packet_id, packet); } - void Client::set_target(const unsigned long long &id) const { + void Client::send_set_target(const unsigned long long &id) const { send_motion_packet(0x04, id); } - void Client::clear_target() const { + void Client::send_clear_target() const { send_motion_packet(0x04, {}); } - void Client::interact_target(const unsigned long long &index) const { + void Client::send_interact_target(const unsigned long long &index) const { send_motion_packet(0x11, index); } - void Client::use_skill(const flyff::SkillID &id, unsigned long long target) const { - send_motion_packet(0x5, static_cast(id), target); + void Client::send_use_skill(const flyff::SkillID &id, unsigned long long unknown) const { + send_motion_packet(0x5, static_cast(id), unknown); + } + + void Client::send_follow_target(const unsigned long long &id) const { + send_motion_packet(0x10, id); } void Client::send_move_to(const double &x, const double &y, const double &z) const { @@ -188,16 +192,22 @@ find_skill_buff(const flyff::Pointer &mover, const flyff::SkillID template std::vector -check_rebuff(const flyff::Pointer &player, const flyff::SkillID (&buffs_to_check)[size]) { +check_rebuff(const flyff::Pointer& buffer, const flyff::Pointer &target, + const flyff::SkillID (&buffs_to_check)[size]) { const auto &neuz = flyff::Neuz::instance(); auto result = std::vector(); for (const auto &skill_index: buffs_to_check) { - const auto &buff = find_skill_buff(player, skill_index); + const auto &buff = find_skill_buff(target, skill_index); const auto &skill_property = flyff::Neuz::get_skill_property(skill_index); + const auto player_skill_level = buffer->get_skill_level(skill_index); + // Only check for the buff if the buffer actually has the skill. + if(player_skill_level <= 0) { + continue; + } + // If a buff is active if (buff) { - auto player_skill_level = player->get_skill_level(skill_index); // For some reason it's one off... auto current_skill_level = buff->level + 1; auto buff_property = reinterpret_cast( @@ -239,47 +249,52 @@ flyff::Pointer find_first_equippable_item(const flyf return flyff::Pointer(highest); } - -bool is_running = false; flyff::Vector3 start_position = {0}; // The object property id of the monster to grind. int object_property_index = 0; +flyff::MoverID current_heal_target = 0; + +enum class ScriptType { + Off, + Attacker, + Healer +}; + +ScriptType script = ScriptType::Off; + void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *user_data) { const auto &client = fugg::Client::instance(); - if (event->keyCode == 220) { - const auto &player = client.player; + if (event->keyCode == 220 && script == ScriptType::Off) { + if (!client.player) + return; - auto items = player->inventory.begin(); - - std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl; - std::cout << "Player has " << player->get_hp_percent() << "% HP" << std::endl; - - for (auto i = 0; i < player->get_inventory_slots(); i++) { - - if (items[i].property && items[i].property->is_food()) { - std::cout << client.get_text(items[i].property->name) << ": " - << "Is food? " << (items[i].property->is_food() ? "Yes" : "No") << ", " - << "Can use? " << (player->can_use_item(items[i].property) ? "Yes" : "No") - << std::endl; - } - -// if (items[i].property && -// items[i].property->is_food() && -// player->can_use_item(items[i].property)) { -// std::string str = "Eating "; -// str.append(client.get_text(items[i].property->name)); -// str.append(" because HP is below 75%"); -// -// client.show_message(str); -// -// client.send_use_item_in_inventory(i); -// -// break; -// } + if (client.player->selected_target == 0) { + client.show_message("No heal target selected.", {0xFF, 0, 0}); + return; } + auto target = client.get_mover(client.player->selected_target); + if (!target) { + client.show_message("No heal target selected.", {0xFF, 0xFF, 0}); + return; + } + + std::string str = "I'm going to heal "; + str.append(client.get_text(target->name)); + str.append("get_level())); + str.append(">"); + client.show_message(str); + + current_heal_target = client.player->selected_target; + script = ScriptType::Healer; + + client.show_message("Bot started"); +// std::cout << "Velocity: " << client.player->delta_velocity << std::endl; + + // if (!main_hand || main_hand->item_kind3 != flyff::ItemProperty::CheerStick) { // const auto &stick = find_first_equippable_item(flyff::ItemProperty::CheerStick); // @@ -303,9 +318,9 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // static_cast(test->property) // ); - // std::cout << "BuffSkill " + // std::cout << "BuffSkill " // << client.get_text(skill_property->name) - // << " ReqLv. " << skill_property->required_level + // << " ReqLv. " << skill_property->required_level // << " Lv." << skill_property->level // << " Id: " << reinterpret_cast(skill_property->id) // << " Remaining: " << (test->get_time_remaining() / 1000) @@ -314,7 +329,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // } // - // clear_target(); + // send_clear_target(); // auto items = player->inventory.begin(); // auto length = ((uintptr_t)player->inventory.end() - (uintptr_t)player->inventory.begin()) / 0x60; @@ -353,14 +368,14 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // if(stick_index != -1) { // // Use skill Heal - // use_skill(0x2c, 10); + // send_use_skill(0x2c, 10); // } else { // client.show_message("Could not find a stick to heal myself.", { 0xFF, 0, 0 }); // } } // BracketLeft - if (event->keyCode == 219 && !is_running) { + if (event->keyCode == 219 && script == ScriptType::Off) { if (!client.player) return; @@ -386,14 +401,14 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u start_position = {client.player->position.x, client.player->position.y, client.player->position.z}; std::cout << "Start botting at " << start_position << std::endl; - is_running = true; + script = ScriptType::Attacker; client.show_message("Bot started"); } if (event->keyCode == 221) { - if (is_running) { - is_running = false; + if (script != ScriptType::Off) { + script = ScriptType::Off; client.show_message("Bot stopped"); } else { @@ -438,12 +453,12 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u // << "Is this food ? " << (items[i].property->is_food_item() ? "Yes" : "No") // << std::endl; // } - // } + // } } } } -flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) { +flyff::MoverID find_closest_target() { auto &neuz = flyff::Neuz::instance(); auto &client = fugg::Client::instance(); @@ -485,12 +500,6 @@ flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) { } while (current); if (closest) { - neuz.player->selected_target = closest->object_id; - client.set_target(closest->object_id); - - neuz.player->move_toward_target = closest->object_id; - client.interact_target(1); - return closest->object_id; } @@ -539,223 +548,312 @@ flyff::MoverID find_next_item() { return 0; } -void interact(flyff::MoverID id) { - const auto &neuz = flyff::Neuz::instance(); +void interact(flyff::MoverID id, uint32_t action) { const auto &client = fugg::Client::instance(); - if (!neuz.player) + if (!client.player) return; - neuz.player->selected_target = id; - client.set_target(id); + client.player->selected_target = id; + client.send_set_target(id); - neuz.player->move_toward_target = id; - client.interact_target(1); + client.player->move_toward_target = id; + client.send_interact_target(action); } flyff::MoverID current_target = 0; flyff::MoverID current_pickup_item = 0; -void bot_tick() { +void attacker_script() { const auto &neuz = flyff::Neuz::instance(); const auto &client = fugg::Client::instance(); 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; + if (neuz.player->is_dead()) { + neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00}); + script = ScriptType::Off; + return; + } - // printf("%#010x\n", neuz.player->get_state()); + const auto &player = neuz.player; - if (is_running) { - if (neuz.player->is_dead()) { - neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00}); - is_running = false; - return; + // if is_idle: + // if item_target: + // pickup_item() + // elif attacK_target: + // attack_target() + + if (neuz.player->get_hp_percent() < 50) { + // neuz.show_message("Fooding because HP is under 75%");W + auto items = player->inventory.begin(); + std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl; + for (auto i = 0; i < player->get_inventory_slots(); i++) { + if (items[i].property && + items[i].property->is_food() && + player->can_use_item(items[i].property)) { + std::string str = "Eating "; + str.append(neuz.get_text(items[i].property->name)); + str.append(" because HP is below 75%"); + + neuz.show_message(str); + + client.send_use_item_in_inventory(i); + + break; + } + } + } + + if (neuz.player->get_move_state() == 1 && + !neuz.player->is_attacking()) { + + + // Check buffs. + static constexpr flyff::SkillID buffs_to_check[] = { + flyff::SkillID::HeapUp, + flyff::SkillID::Haste, + flyff::SkillID::Patience, + flyff::SkillID::BeefUp, + }; + + auto item = neuz.get_mover(current_pickup_item); + auto monster = neuz.get_mover(current_target); + + if (neuz.player->get_job() == flyff::JobID::Assist) { + const auto &main_hand = player->get_equipped_item(flyff::Part::MainHand); + const auto &off_hand = player->get_equipped_item(flyff::Part::Shield); + + auto buffs = check_rebuff(neuz.player, neuz.player, buffs_to_check); + if (!buffs.empty() && (!item || item->is_despawned) && (!monster || monster->is_dead())) { + const auto skill_index = buffs.back(); + if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::CheerStick) { + const auto &stick = find_first_equippable_item(flyff::ItemKind3::CheerStick); + + if (stick) { + buffs.pop_back(); + + client.send_use_item_in_inventory(stick->index); + client.send_use_skill(skill_index); + return; + } else { + neuz.show_message("Unable to find a stick", {0xFF, 0, 0}); + } + } else { + buffs.pop_back(); + client.send_use_skill(skill_index); + return; + } + } + + if (buffs.empty()) { + if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::KnuckleHammer) { + const auto &knuckle = find_first_equippable_item(flyff::ItemKind3::KnuckleHammer); + + if (knuckle) { + client.send_use_item_in_inventory(knuckle->index); + } else { + neuz.show_message("Unable to find a knuckle", {0xFF, 0, 0}); + } + } + + if (!off_hand || off_hand->item_kind3 != flyff::ItemKind3::Shield) { + const auto &shield = find_first_equippable_item(flyff::ItemKind3::Shield); + + if (shield) { + client.send_use_item_in_inventory(shield->index); + } else { + neuz.show_message("Unable to find a shield", {0xFF, 0, 0}); + } + } + } } - const auto &player = neuz.player; + if (item && !item->is_despawned && neuz.player->move_toward_target == 0) { + // Pickup + interact(item->object_id, 1); + } else if (monster && !monster->is_dead() && neuz.player->move_toward_target == 0) { + // Attack + interact(monster->object_id, 1); + // neuz.player->attack_target = monster->object_id; + } else if ((!item || item->is_despawned) && + (!monster || monster->is_dead())) { + std::cout << "No item, no target. Searching..." << std::endl; - // if is_idle: - // if item_target: - // pickup_item() - // elif attacK_target: - // attack_target() + // First check all mobs if they attacked me (aggro ones). + for (const auto &id: client.player->enemies) { + const auto &mover = client.get_mover(id); - if (neuz.player->get_hp_percent() < 75) { - // neuz.show_message("Fooding because HP is under 75%");W - auto items = player->inventory.begin(); - std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl; - for (auto i = 0; i < player->get_inventory_slots(); i++) { - if (items[i].property && - items[i].property->is_food() && - player->can_use_item(items[i].property)) { - std::string str = "Eating "; - str.append(neuz.get_text(items[i].property->name)); - str.append(" because HP is below 75%"); + if (mover) { + std::string str = "Attacking "; + str.append(mover->name); + str.append(" because it is my enemy."); + + current_target = id; + interact(id, 1); neuz.show_message(str); - - client.send_use_item_in_inventory(i); - - break; + return; } } - } + // No item target and no attack target + current_pickup_item = find_next_item(); + item = neuz.get_mover(current_pickup_item); + if (item) { + auto *prop = reinterpret_cast( + static_cast(item->property) + ); - if (neuz.player->get_move_state() == 1 && - !neuz.player->is_attacking()) { + std::string str = "Picking up "; + str.append(neuz.get_text(prop->name)); + interact(item->object_id, 1); - // Check buffs. - static constexpr flyff::SkillID buffs_to_check[] = { - flyff::SkillID::HeapUp, - flyff::SkillID::Haste, - flyff::SkillID::Patience, - flyff::SkillID::BeefUp, - }; + neuz.show_message(str); + return; + } else { + current_target = find_closest_target(); - auto item = neuz.get_mover(current_pickup_item); - auto monster = neuz.get_mover(current_target); + monster = neuz.get_mover(current_target); + if (monster) { + std::string str = "Attacking "; + str.append(monster->name); - if (neuz.player->get_job() == flyff::JobID::Assist) { - const auto &main_hand = player->get_equipped_item(flyff::Part::MainHand); - const auto &off_hand = player->get_equipped_item(flyff::Part::Shield); - - auto buffs = check_rebuff(neuz.player, buffs_to_check); - if (!buffs.empty() && (!item || item->is_despawned) && (!monster || monster->is_dead())) { - const auto skill_index = buffs.back(); - if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::CheerStick) { - const auto &stick = find_first_equippable_item(flyff::ItemKind3::CheerStick); - - if (stick) { - buffs.pop_back(); - - client.send_use_item_in_inventory(stick->index); - client.use_skill(skill_index); - return; - } else { - neuz.show_message("Unable to find a stick", {0xFF, 0, 0}); - } - } else { - buffs.pop_back(); - client.use_skill(skill_index); - return; - } - } - - if (buffs.empty()) { - if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::KnuckleHammer) { - const auto &knuckle = find_first_equippable_item(flyff::ItemKind3::KnuckleHammer); - - if (knuckle) { - client.send_use_item_in_inventory(knuckle->index); - } else { - neuz.show_message("Unable to find a knuckle", {0xFF, 0, 0}); - } - } - - if (!off_hand || off_hand->item_kind3 != flyff::ItemKind3::Shield) { - const auto &shield = find_first_equippable_item(flyff::ItemKind3::Shield); - - if (shield) { - client.send_use_item_in_inventory(shield->index); - } else { - neuz.show_message("Unable to find a shield", {0xFF, 0, 0}); - } - } - } - } - - if (item && !item->is_despawned && neuz.player->move_toward_target == 0) { - // Pickup - interact(item->object_id); - } else if (monster && !monster->is_dead() && neuz.player->move_toward_target == 0) { - // Attack - interact(monster->object_id); - // neuz.player->attack_target = monster->object_id; - } else if ((!item || item->is_despawned) && - (!monster || monster->is_dead())) { - std::cout << "No item, no target. Searching..." << std::endl; - - // First check all mobs if they attacked me (aggro ones). - auto current = neuz.movers.first; - do { - const auto &mover = current->mover; - - if (mover->type == flyff::ObjectType::Mover && - current->hash != neuz.player_object_id && - !mover->is_dead() && - // If it's a monster that has me targetted... - mover->last_attacked_target == neuz.player_object_id && - // ...and is tracking me - mover->follow_target == neuz.player_object_id) { - - current_target = attack_next_target(start_position); - - monster = neuz.get_mover(current_target); - std::string str = "Attacking "; - str.append(monster->name); - str.append(" because it attacked me."); - - interact(monster->object_id); - - neuz.show_message(str); - return; - } - - current = current->next; - } while (current); - - // No item target and no attack target - current_pickup_item = find_next_item(); - item = neuz.get_mover(current_pickup_item); - if (item) { - auto *prop = reinterpret_cast( - static_cast(item->property) - ); - - std::string str = "Picking up "; - str.append(neuz.get_text(prop->name)); - - interact(item->object_id); + interact(current_target, 1); neuz.show_message(str); } else { - current_target = attack_next_target(start_position); - - monster = neuz.get_mover(current_target); - if (monster) { - std::string str = "Attacking "; - str.append(monster->name); - - std::cout << str << std::endl; - - interact(monster->object_id); - // neuz.player->attack_target = monster->object_id; - - neuz.show_message(str); - } else { - neuz.show_message("Unable to find target."); - } + neuz.show_message("Unable to find target."); } } } - } else { - // Reset current target is not running. - current_target = 0; - current_pickup_item = 0; + } +} + + +void healer_script() { + const auto &client = fugg::Client::instance(); + + if (!client.player) + return; + + if (client.player->is_dead()) { + client.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00}); + script = ScriptType::Off; + return; + } + + if (client.player->get_move_state() == 1 && + !client.player->is_attacking()) { + + if (client.player->selected_target != current_heal_target) { + client.send_set_target(current_heal_target); + client.player->selected_target = current_heal_target; + + client.show_message("Selected target"); + } + + if (client.player->follow_target != current_heal_target) { + client.send_follow_target(current_heal_target); + client.player->follow_target = current_heal_target; + + client.show_message("Following target"); + } + + const auto &target = client.get_mover(current_heal_target); + if (target) { + // If the target has been hit, heal him. + if (target->get_hp_percent() < 100) { + client.show_message("Healing target"); + + client.send_use_skill(flyff::SkillID::Heal); + return; + } + // If I'm hit, heal myself. + if(client.player->get_hp_percent() < 75) { + client.send_clear_target(); + client.player->selected_target = 0; + + client.send_use_skill(flyff::SkillID::Heal); + return; + } + // Check for rebuff on the target + { + // For target, check all buffs. + static constexpr flyff::SkillID buffs_to_check[] = { + flyff::SkillID::MentalSign, + flyff::SkillID::Patience, + flyff::SkillID::QuickStep, + flyff::SkillID::HeapUp, + flyff::SkillID::Haste, + flyff::SkillID::BeefUp, + flyff::SkillID::Accuracy, + flyff::SkillID::CatsReflex, + flyff::SkillID::CannonBall + }; + + auto buffs = check_rebuff(client.player, target, buffs_to_check); + if (!buffs.empty()) { + auto skill_index = buffs.back(); + buffs.pop_back(); + + const auto& skill = fugg::Client::get_skill_property(skill_index); + std::string str = "Buffing target with"; + str.append(client.get_text(skill->name)); + client.show_message(str); + + client.send_use_skill(skill_index); + return; + } + } + // Check for rebuff on yourself + if(!target->is_in_combat(1500)){ + // For FS itself, only these selected buffs. + static constexpr flyff::SkillID buffs_to_check[] = { + flyff::SkillID::MentalSign, + flyff::SkillID::QuickStep, + flyff::SkillID::Patience, + flyff::SkillID::HeapUp, + flyff::SkillID::Haste, + flyff::SkillID::Prevention + }; + + auto buffs = check_rebuff(client.player, client.player, buffs_to_check); + if (!buffs.empty()) { + auto skill_index = buffs.back(); + buffs.pop_back(); + + client.send_clear_target(); + client.player->selected_target = 0; + + client.send_use_skill(skill_index); + return; + } + } + } else { + client.show_message("Can't find target!", {0xFF, 0, 0}); + } } } void before_main_loop() { - bot_tick(); + switch (script) { + case ScriptType::Attacker: + attacker_script(); + break; + + case ScriptType::Healer: + healer_script(); + break; + + default: + // Reset current target is not running. + current_target = 0; + current_pickup_item = 0; + + break; + } } void after_main_loop() { diff --git a/fugg-client/src/Client.h b/fugg-client/src/Client.h index c5205c1..b761bc8 100644 --- a/fugg-client/src/Client.h +++ b/fugg-client/src/Client.h @@ -28,13 +28,15 @@ namespace fugg { void send_motion_packet(const uint32_t &action, unsigned long long param0 = 0, unsigned long long param1 = 0, unsigned long long param2 = 0, unsigned long long param3 = 0) const; - void set_target(const unsigned long long &id) const; + void send_set_target(const unsigned long long &id) const; - void clear_target() const; + void send_clear_target() const; - void interact_target(const unsigned long long &index) const; - void use_skill(const flyff::SkillID &id, unsigned long long target = -1) const; + void send_interact_target(const unsigned long long &index) const; + + void send_use_skill(const flyff::SkillID &id, unsigned long long unknown = -1) const; + void send_follow_target(const unsigned long long &id) const; void send_move_to(const double &x, const double &y, const double &z) const; void send_chat_message(const std::string &message) const; diff --git a/fugg-client/src/behaviour/Action.h b/fugg-client/src/behaviour/Action.h new file mode 100644 index 0000000..3652f93 --- /dev/null +++ b/fugg-client/src/behaviour/Action.h @@ -0,0 +1,57 @@ +// +// Created by main on 21-10-22. +// + +#ifndef FUGG_ACTION_H +#define FUGG_ACTION_H + +#include "../Client.h" + +namespace fugg { + class Action { + + public: + enum class State : unsigned char { + Running, + Failed, + Succeeded + }; + + virtual State evaluate(Client &client) = 0; + }; + + class StatefulAction : Action { + virtual State start() = 0; + virtual State run() = 0; + virtual State stop() = 0; + }; + + + class ActionAttack : Action { + const flyff::MoverID target_id; + + public: + explicit ActionAttack(flyff::MoverID id) : target_id(id) { } + + State evaluate(Client &client) override { + const auto& target = client.get_mover(target_id); + + if(!target) return State::Failed; + + if(client.player->selected_target != target_id) { + client.player->selected_target = target_id; + client.send_set_target(target_id); + } + + if(client.player->move_toward_target != target_id) { + client.player->move_toward_target = target_id; + client.send_interact_target(1); + } + + return State::Succeeded; + }; + }; +}; + + +#endif //FUGG_ACTION_H diff --git a/fugg-client/src/behaviour/Script.h b/fugg-client/src/behaviour/Script.h new file mode 100644 index 0000000..c83a5c4 --- /dev/null +++ b/fugg-client/src/behaviour/Script.h @@ -0,0 +1,19 @@ +// +// Created by main on 25-10-22. +// + +#ifndef FUGG_SCRIPT_H +#define FUGG_SCRIPT_H + +#include "Action.h" + +namespace fugg { + class Script { + + public: + virtual Action evaluate(const Client& client) = 0; + }; + +}; + +#endif //FUGG_SCRIPT_H