Lots of refactoring
This commit is contained in:
parent
cca6f82dcb
commit
4a5b4790d4
|
|
@ -8,7 +8,7 @@ add_library(
|
||||||
"include/flyff.h"
|
"include/flyff.h"
|
||||||
src/core.h
|
src/core.h
|
||||||
src/skill/SkillProperty.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_include_directories(flyff-api PUBLIC "include")
|
||||||
target_link_libraries(flyff-api PUBLIC flyff-client fugg-api)
|
target_link_libraries(flyff-api PUBLIC flyff-client fugg-api)
|
||||||
|
|
@ -188,6 +188,10 @@ namespace flyff {
|
||||||
T *end() const {
|
T *end() const {
|
||||||
return static_cast<T *>(end_);
|
return static_cast<T *>(end_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return static_cast<size_t>(end_ - begin_);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Vector<char>) == sizeof(std::vector<char>),
|
static_assert(sizeof(Vector<char>) == sizeof(std::vector<char>),
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ namespace flyff {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mover::is_in_combat() const {
|
bool Mover::is_in_combat(uint32_t millis) const {
|
||||||
const auto &neuz = flyff::Neuz::instance();
|
const auto &neuz = flyff::Neuz::instance();
|
||||||
// 10 seconds
|
// 10 seconds
|
||||||
return neuz.current_time - last_combat < 10000000;
|
return neuz.current_time - last_combat < (millis * 1000);
|
||||||
}
|
}
|
||||||
}; // namespace flyff
|
}; // namespace flyff
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../../item/InventoryItem.h"
|
#include "../../item/InventoryItem.h"
|
||||||
#include "../../item/Part.h"
|
#include "../../item/Part.h"
|
||||||
#include "JobProperty.h"
|
#include "JobProperty.h"
|
||||||
|
#include "ParamID.h"
|
||||||
|
|
||||||
namespace flyff {
|
namespace flyff {
|
||||||
namespace raw {
|
namespace raw {
|
||||||
|
|
@ -36,9 +37,6 @@ namespace flyff {
|
||||||
|
|
||||||
using Parameter = unsigned long;
|
using Parameter = unsigned long;
|
||||||
|
|
||||||
static constexpr Parameter DST_HP_MAX = 0x2c;
|
|
||||||
static constexpr Parameter DST_HP_MAX_RATE = 0x35;
|
|
||||||
|
|
||||||
using ObjectStateFlags = Object::StateFlags;
|
using ObjectStateFlags = Object::StateFlags;
|
||||||
using ObjectState = Object::State;
|
using ObjectState = Object::State;
|
||||||
|
|
||||||
|
|
@ -98,7 +96,7 @@ namespace flyff {
|
||||||
return fn(kMemory.to_inside(this));
|
return fn(kMemory.to_inside(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_id() const {
|
uint32_t get_id() const {
|
||||||
using Fn = FunctionPointer<u32, u32>;
|
using Fn = FunctionPointer<u32, u32>;
|
||||||
const auto &fn = fugg::function_ref<Fn>(vtable->get_id);
|
const auto &fn = fugg::function_ref<Fn>(vtable->get_id);
|
||||||
|
|
||||||
|
|
@ -113,14 +111,15 @@ namespace flyff {
|
||||||
|
|
||||||
DEFINE_MEMBER(0x18, Matrix4, world_matrix);
|
DEFINE_MEMBER(0x18, Matrix4, world_matrix);
|
||||||
|
|
||||||
DEFINE_MEMBER(152, Vector3, position);
|
DEFINE_MEMBER(152, const Vector3, position);
|
||||||
DEFINE_MEMBER(164, Vector3, rotation);
|
DEFINE_MEMBER(164, const Vector3, rotation);
|
||||||
|
|
||||||
DEFINE_MEMBER(188, const Pointer<const ObjectProperty>, property);
|
DEFINE_MEMBER(188, const Pointer<const ObjectProperty>, property);
|
||||||
|
|
||||||
DEFINE_MEMBER(212, int, property_id);
|
DEFINE_MEMBER(212, const int, property_id);
|
||||||
DEFINE_MEMBER(216, bool, is_despawned);
|
DEFINE_MEMBER(216, const bool, is_despawned);
|
||||||
DEFINE_MEMBER(352, MoverID, object_id);
|
|
||||||
|
DEFINE_MEMBER(352, const MoverID, object_id);
|
||||||
|
|
||||||
DEFINE_MEMBER(920, Parameter, adjusted_parameters[MAX_PARAM]);
|
DEFINE_MEMBER(920, Parameter, adjusted_parameters[MAX_PARAM]);
|
||||||
DEFINE_MEMBER(1248, Parameter, changed_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(2020, const String, name);
|
||||||
|
|
||||||
|
DEFINE_MEMBER(1616, const Vector<flyff::MoverID>, enemies);
|
||||||
DEFINE_MEMBER(1628, Vector3, move_target);
|
DEFINE_MEMBER(1628, Vector3, move_target);
|
||||||
|
|
||||||
|
DEFINE_MEMBER(1652, Vector3, delta_velocity);
|
||||||
|
|
||||||
DEFINE_MEMBER(1688, unsigned long long, last_combat);
|
DEFINE_MEMBER(1688, unsigned long long, last_combat);
|
||||||
|
|
||||||
DEFINE_MEMBER(1728, MoverID, move_toward_target);
|
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);
|
DEFINE_MEMBER(1744, MoverID, selected_target);
|
||||||
// The id of the target that it hit last.
|
// The id of the target that it hit last.
|
||||||
DEFINE_MEMBER(1752, MoverID, attack_target);
|
DEFINE_MEMBER(1752, MoverID, attack_target);
|
||||||
|
|
@ -153,8 +156,6 @@ namespace flyff {
|
||||||
|
|
||||||
DEFINE_MEMBER(204, const ObjectType, type);
|
DEFINE_MEMBER(204, const ObjectType, type);
|
||||||
|
|
||||||
DEFINE_MEMBER(216, uint32_t, existence_check);
|
|
||||||
|
|
||||||
DEFINE_MEMBER(1804, uint32_t, object_state);
|
DEFINE_MEMBER(1804, uint32_t, object_state);
|
||||||
DEFINE_MEMBER(1808, uint32_t, object_state_flags);
|
DEFINE_MEMBER(1808, uint32_t, object_state_flags);
|
||||||
|
|
||||||
|
|
@ -169,9 +170,9 @@ namespace flyff {
|
||||||
|
|
||||||
DEFINE_MEMBER(2432, const flyff::Pointer<const JobProperty>, job_property);
|
DEFINE_MEMBER(2432, const flyff::Pointer<const JobProperty>, job_property);
|
||||||
|
|
||||||
DEFINE_MEMBER(3224, Timestamp, last_food_time);
|
DEFINE_MEMBER(3224, const Timestamp, last_food_time);
|
||||||
DEFINE_MEMBER(3248, Timestamp, last_refresher_time);
|
DEFINE_MEMBER(3248, const Timestamp, last_refresher_time);
|
||||||
DEFINE_MEMBER(3256, Timestamp, last_vitaldrink_time);
|
DEFINE_MEMBER(3256, const Timestamp, last_vitaldrink_time);
|
||||||
|
|
||||||
DEFINE_MEMBER(3424, Vector<Skill>, skills);
|
DEFINE_MEMBER(3424, Vector<Skill>, skills);
|
||||||
|
|
||||||
|
|
@ -199,9 +200,9 @@ namespace flyff {
|
||||||
return max_inventory_slots - locked_inventory_slots;
|
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);
|
Parameter changeParam = get_change_param(index);
|
||||||
if (changeParam != 0x7FFFFFFF)
|
if (changeParam != 0x7FFFFFFF)
|
||||||
return changeParam;
|
return changeParam;
|
||||||
|
|
@ -213,13 +214,16 @@ namespace flyff {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter get_adjust_param(Parameter index) const {
|
Parameter get_adjust_param(ParamID index) const {
|
||||||
|
auto id = static_cast<uint32_t>(index);
|
||||||
// Find these values in CMover::Init
|
// 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 {
|
Parameter get_change_param(ParamID index) const {
|
||||||
return changed_parameters[index] ^ adj_param ^ index * 0x41c64e6d + 0xb5a52d1a;
|
auto id = static_cast<uint32_t>(index);
|
||||||
|
|
||||||
|
return changed_parameters[id] ^ adj_param ^ id * 0x41c64e6d + 0xb5a52d1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_hp() const {
|
u32 get_hp() const {
|
||||||
|
|
@ -236,8 +240,8 @@ namespace flyff {
|
||||||
|
|
||||||
uint32_t get_max_hp() const {
|
uint32_t get_max_hp() const {
|
||||||
float factor = 1.0f;
|
float factor = 1.0f;
|
||||||
int result = get_param(DST_HP_MAX, get_max_origin_hp());
|
auto result = get_param(ParamID::MaxHitPoint, get_max_origin_hp());
|
||||||
int percent = get_param(DST_HP_MAX_RATE, 0);
|
auto percent = get_param(ParamID::MaxHitPointScaling, 0);
|
||||||
|
|
||||||
factor += (float) percent / (float) 100;
|
factor += (float) percent / (float) 100;
|
||||||
result = static_cast<float>(result) * factor;
|
result = static_cast<float>(result) * factor;
|
||||||
|
|
@ -246,7 +250,7 @@ namespace flyff {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_hp_percent(int percent = 100) const {
|
uint32_t get_hp_percent(int percent = 100) const {
|
||||||
int max = get_max_hp();
|
auto max = get_max_hp();
|
||||||
if (max == 0) return 0;
|
if (max == 0) return 0;
|
||||||
|
|
||||||
return get_hp() * percent / max;
|
return get_hp() * percent / max;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by main on 25-10-22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FUGG_PARAMID_H
|
||||||
|
#define FUGG_PARAMID_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace flyff {
|
||||||
|
enum class ParamID : uint32_t {
|
||||||
|
// DST_HP_MAX
|
||||||
|
MaxHitPoint = 44,
|
||||||
|
// DST_HP_MAX_RATE
|
||||||
|
MaxHitPointScaling = 53,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FUGG_PARAMID_H
|
||||||
|
|
@ -1051403,9 +1051403,24 @@ void w2c_f2316(u32 w2c_p0) {
|
||||||
w2c_i0 = w2c_p0;
|
w2c_i0 = w2c_p0;
|
||||||
w2c_i0 = i32_load((&w2c_memory), (u64)(w2c_i0) + 4u);
|
w2c_i0 = i32_load((&w2c_memory), (u64)(w2c_i0) + 4u);
|
||||||
w2c_l4 = w2c_i0;
|
w2c_l4 = w2c_i0;
|
||||||
|
|
||||||
|
const uintptr_t end = w2c_l4;
|
||||||
|
|
||||||
w2c_i1 = w2c_p0;
|
w2c_i1 = w2c_p0;
|
||||||
w2c_i1 = i32_load((&w2c_memory), (u64)(w2c_i1));
|
w2c_i1 = i32_load((&w2c_memory), (u64)(w2c_i1));
|
||||||
w2c_l2 = 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_i0 -= w2c_i1;
|
||||||
w2c_l7 = w2c_i0;
|
w2c_l7 = w2c_i0;
|
||||||
w2c_i0 = 9u;
|
w2c_i0 = 9u;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ add_executable(
|
||||||
"src/export/embind.cpp"
|
"src/export/embind.cpp"
|
||||||
"src/export/env.cpp"
|
"src/export/env.cpp"
|
||||||
"src/export/platform.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
|
# Flyff is based on c++14
|
||||||
add_definitions(-std=c++14 -Os)
|
add_definitions(-std=c++14 -Os)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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() {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
//
|
|
||||||
// Created by main on 21-10-22.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef FUGG_BOT_H
|
|
||||||
#define FUGG_BOT_H
|
|
||||||
|
|
||||||
#include <flyff.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -115,20 +115,24 @@ namespace fugg {
|
||||||
send_packet(motion_packet_id, packet);
|
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);
|
send_motion_packet(0x04, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::clear_target() const {
|
void Client::send_clear_target() const {
|
||||||
send_motion_packet(0x04, {});
|
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);
|
send_motion_packet(0x11, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::use_skill(const flyff::SkillID &id, unsigned long long target) const {
|
void Client::send_use_skill(const flyff::SkillID &id, unsigned long long unknown) const {
|
||||||
send_motion_packet(0x5, static_cast<unsigned long long>(id), target);
|
send_motion_packet(0x5, static_cast<unsigned long long>(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 {
|
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<flyff::Mover> &mover, const flyff::SkillID
|
||||||
|
|
||||||
template<size_t size>
|
template<size_t size>
|
||||||
std::vector<flyff::SkillID>
|
std::vector<flyff::SkillID>
|
||||||
check_rebuff(const flyff::Pointer<flyff::Mover> &player, const flyff::SkillID (&buffs_to_check)[size]) {
|
check_rebuff(const flyff::Pointer<flyff::Mover>& buffer, const flyff::Pointer<flyff::Mover> &target,
|
||||||
|
const flyff::SkillID (&buffs_to_check)[size]) {
|
||||||
const auto &neuz = flyff::Neuz::instance();
|
const auto &neuz = flyff::Neuz::instance();
|
||||||
|
|
||||||
auto result = std::vector<flyff::SkillID>();
|
auto result = std::vector<flyff::SkillID>();
|
||||||
for (const auto &skill_index: buffs_to_check) {
|
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 &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 a buff is active
|
||||||
if (buff) {
|
if (buff) {
|
||||||
auto player_skill_level = player->get_skill_level(skill_index);
|
|
||||||
// For some reason it's one off...
|
// For some reason it's one off...
|
||||||
auto current_skill_level = buff->level + 1;
|
auto current_skill_level = buff->level + 1;
|
||||||
auto buff_property = reinterpret_cast<const flyff::SkillProperty *>(
|
auto buff_property = reinterpret_cast<const flyff::SkillProperty *>(
|
||||||
|
|
@ -239,47 +249,52 @@ flyff::Pointer<const flyff::InventoryItem> find_first_equippable_item(const flyf
|
||||||
return flyff::Pointer<const flyff::InventoryItem>(highest);
|
return flyff::Pointer<const flyff::InventoryItem>(highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_running = false;
|
|
||||||
flyff::Vector3 start_position = {0};
|
flyff::Vector3 start_position = {0};
|
||||||
// The object property id of the monster to grind.
|
// The object property id of the monster to grind.
|
||||||
int object_property_index = 0;
|
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) {
|
void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *user_data) {
|
||||||
const auto &client = fugg::Client::instance();
|
const auto &client = fugg::Client::instance();
|
||||||
|
|
||||||
if (event->keyCode == 220) {
|
if (event->keyCode == 220 && script == ScriptType::Off) {
|
||||||
const auto &player = client.player;
|
if (!client.player)
|
||||||
|
return;
|
||||||
|
|
||||||
auto items = player->inventory.begin();
|
if (client.player->selected_target == 0) {
|
||||||
|
client.show_message("No heal target selected.", {0xFF, 0, 0});
|
||||||
std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl;
|
return;
|
||||||
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 &&
|
auto target = client.get_mover(client.player->selected_target);
|
||||||
// items[i].property->is_food() &&
|
if (!target) {
|
||||||
// player->can_use_item(items[i].property)) {
|
client.show_message("No heal target selected.", {0xFF, 0xFF, 0});
|
||||||
// std::string str = "Eating ";
|
return;
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string str = "I'm going to heal ";
|
||||||
|
str.append(client.get_text(target->name));
|
||||||
|
str.append("<Lv. ");
|
||||||
|
str.append(std::to_string(target->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) {
|
// if (!main_hand || main_hand->item_kind3 != flyff::ItemProperty::CheerStick) {
|
||||||
// const auto &stick = find_first_equippable_item(flyff::ItemProperty::CheerStick);
|
// const auto &stick = find_first_equippable_item(flyff::ItemProperty::CheerStick);
|
||||||
//
|
//
|
||||||
|
|
@ -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 items = player->inventory.begin();
|
||||||
// auto length = ((uintptr_t)player->inventory.end() - (uintptr_t)player->inventory.begin()) / 0x60;
|
// 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) {
|
// if(stick_index != -1) {
|
||||||
// // Use skill Heal
|
// // Use skill Heal
|
||||||
// use_skill(0x2c, 10);
|
// send_use_skill(0x2c, 10);
|
||||||
// } else {
|
// } else {
|
||||||
// client.show_message("Could not find a stick to heal myself.", { 0xFF, 0, 0 });
|
// client.show_message("Could not find a stick to heal myself.", { 0xFF, 0, 0 });
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// BracketLeft
|
// BracketLeft
|
||||||
if (event->keyCode == 219 && !is_running) {
|
if (event->keyCode == 219 && script == ScriptType::Off) {
|
||||||
if (!client.player)
|
if (!client.player)
|
||||||
return;
|
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};
|
start_position = {client.player->position.x, client.player->position.y, client.player->position.z};
|
||||||
std::cout << "Start botting at " << start_position << std::endl;
|
std::cout << "Start botting at " << start_position << std::endl;
|
||||||
|
|
||||||
is_running = true;
|
script = ScriptType::Attacker;
|
||||||
|
|
||||||
client.show_message("Bot started");
|
client.show_message("Bot started");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->keyCode == 221) {
|
if (event->keyCode == 221) {
|
||||||
if (is_running) {
|
if (script != ScriptType::Off) {
|
||||||
is_running = false;
|
script = ScriptType::Off;
|
||||||
|
|
||||||
client.show_message("Bot stopped");
|
client.show_message("Bot stopped");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -443,7 +458,7 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) {
|
flyff::MoverID find_closest_target() {
|
||||||
auto &neuz = flyff::Neuz::instance();
|
auto &neuz = flyff::Neuz::instance();
|
||||||
auto &client = fugg::Client::instance();
|
auto &client = fugg::Client::instance();
|
||||||
|
|
||||||
|
|
@ -485,12 +500,6 @@ flyff::MoverID attack_next_target(flyff::Vector3 const &start_position) {
|
||||||
} while (current);
|
} while (current);
|
||||||
|
|
||||||
if (closest) {
|
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;
|
return closest->object_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -539,44 +548,32 @@ flyff::MoverID find_next_item() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void interact(flyff::MoverID id) {
|
void interact(flyff::MoverID id, uint32_t action) {
|
||||||
const auto &neuz = flyff::Neuz::instance();
|
|
||||||
const auto &client = fugg::Client::instance();
|
const auto &client = fugg::Client::instance();
|
||||||
|
|
||||||
if (!neuz.player)
|
if (!client.player)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
neuz.player->selected_target = id;
|
client.player->selected_target = id;
|
||||||
client.set_target(id);
|
client.send_set_target(id);
|
||||||
|
|
||||||
neuz.player->move_toward_target = id;
|
client.player->move_toward_target = id;
|
||||||
client.interact_target(1);
|
client.send_interact_target(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
flyff::MoverID current_target = 0;
|
flyff::MoverID current_target = 0;
|
||||||
flyff::MoverID current_pickup_item = 0;
|
flyff::MoverID current_pickup_item = 0;
|
||||||
|
|
||||||
void bot_tick() {
|
void attacker_script() {
|
||||||
const auto &neuz = flyff::Neuz::instance();
|
const auto &neuz = flyff::Neuz::instance();
|
||||||
const auto &client = fugg::Client::instance();
|
const auto &client = fugg::Client::instance();
|
||||||
|
|
||||||
if (!neuz.player)
|
if (!neuz.player)
|
||||||
return;
|
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()) {
|
if (neuz.player->is_dead()) {
|
||||||
neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00});
|
neuz.show_message("Player is dead, stopping...", {0xFF, 0x00, 0x00});
|
||||||
is_running = false;
|
script = ScriptType::Off;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -588,7 +585,7 @@ void bot_tick() {
|
||||||
// elif attacK_target:
|
// elif attacK_target:
|
||||||
// attack_target()
|
// attack_target()
|
||||||
|
|
||||||
if (neuz.player->get_hp_percent() < 75) {
|
if (neuz.player->get_hp_percent() < 50) {
|
||||||
// neuz.show_message("Fooding because HP is under 75%");W
|
// neuz.show_message("Fooding because HP is under 75%");W
|
||||||
auto items = player->inventory.begin();
|
auto items = player->inventory.begin();
|
||||||
std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl;
|
std::cout << "Player has " << player->get_inventory_slots() << " slots" << std::endl;
|
||||||
|
|
@ -628,7 +625,7 @@ void bot_tick() {
|
||||||
const auto &main_hand = player->get_equipped_item(flyff::Part::MainHand);
|
const auto &main_hand = player->get_equipped_item(flyff::Part::MainHand);
|
||||||
const auto &off_hand = player->get_equipped_item(flyff::Part::Shield);
|
const auto &off_hand = player->get_equipped_item(flyff::Part::Shield);
|
||||||
|
|
||||||
auto buffs = check_rebuff(neuz.player, buffs_to_check);
|
auto buffs = check_rebuff(neuz.player, neuz.player, buffs_to_check);
|
||||||
if (!buffs.empty() && (!item || item->is_despawned) && (!monster || monster->is_dead())) {
|
if (!buffs.empty() && (!item || item->is_despawned) && (!monster || monster->is_dead())) {
|
||||||
const auto skill_index = buffs.back();
|
const auto skill_index = buffs.back();
|
||||||
if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::CheerStick) {
|
if (!main_hand || main_hand->item_kind3 != flyff::ItemKind3::CheerStick) {
|
||||||
|
|
@ -638,14 +635,14 @@ void bot_tick() {
|
||||||
buffs.pop_back();
|
buffs.pop_back();
|
||||||
|
|
||||||
client.send_use_item_in_inventory(stick->index);
|
client.send_use_item_in_inventory(stick->index);
|
||||||
client.use_skill(skill_index);
|
client.send_use_skill(skill_index);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
neuz.show_message("Unable to find a stick", {0xFF, 0, 0});
|
neuz.show_message("Unable to find a stick", {0xFF, 0, 0});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffs.pop_back();
|
buffs.pop_back();
|
||||||
client.use_skill(skill_index);
|
client.send_use_skill(skill_index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -675,44 +672,31 @@ void bot_tick() {
|
||||||
|
|
||||||
if (item && !item->is_despawned && neuz.player->move_toward_target == 0) {
|
if (item && !item->is_despawned && neuz.player->move_toward_target == 0) {
|
||||||
// Pickup
|
// Pickup
|
||||||
interact(item->object_id);
|
interact(item->object_id, 1);
|
||||||
} else if (monster && !monster->is_dead() && neuz.player->move_toward_target == 0) {
|
} else if (monster && !monster->is_dead() && neuz.player->move_toward_target == 0) {
|
||||||
// Attack
|
// Attack
|
||||||
interact(monster->object_id);
|
interact(monster->object_id, 1);
|
||||||
// neuz.player->attack_target = monster->object_id;
|
// neuz.player->attack_target = monster->object_id;
|
||||||
} else if ((!item || item->is_despawned) &&
|
} else if ((!item || item->is_despawned) &&
|
||||||
(!monster || monster->is_dead())) {
|
(!monster || monster->is_dead())) {
|
||||||
std::cout << "No item, no target. Searching..." << std::endl;
|
std::cout << "No item, no target. Searching..." << std::endl;
|
||||||
|
|
||||||
// First check all mobs if they attacked me (aggro ones).
|
// First check all mobs if they attacked me (aggro ones).
|
||||||
auto current = neuz.movers.first;
|
for (const auto &id: client.player->enemies) {
|
||||||
do {
|
const auto &mover = client.get_mover(id);
|
||||||
const auto &mover = current->mover;
|
|
||||||
|
|
||||||
if (mover->type == flyff::ObjectType::Mover &&
|
if (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 ";
|
std::string str = "Attacking ";
|
||||||
str.append(monster->name);
|
str.append(mover->name);
|
||||||
str.append(" because it attacked me.");
|
str.append(" because it is my enemy.");
|
||||||
|
|
||||||
interact(monster->object_id);
|
current_target = id;
|
||||||
|
interact(id, 1);
|
||||||
|
|
||||||
neuz.show_message(str);
|
neuz.show_message(str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
current = current->next;
|
|
||||||
} while (current);
|
|
||||||
|
|
||||||
// No item target and no attack target
|
// No item target and no attack target
|
||||||
current_pickup_item = find_next_item();
|
current_pickup_item = find_next_item();
|
||||||
item = neuz.get_mover(current_pickup_item);
|
item = neuz.get_mover(current_pickup_item);
|
||||||
|
|
@ -724,21 +708,19 @@ void bot_tick() {
|
||||||
std::string str = "Picking up ";
|
std::string str = "Picking up ";
|
||||||
str.append(neuz.get_text(prop->name));
|
str.append(neuz.get_text(prop->name));
|
||||||
|
|
||||||
interact(item->object_id);
|
interact(item->object_id, 1);
|
||||||
|
|
||||||
neuz.show_message(str);
|
neuz.show_message(str);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
current_target = attack_next_target(start_position);
|
current_target = find_closest_target();
|
||||||
|
|
||||||
monster = neuz.get_mover(current_target);
|
monster = neuz.get_mover(current_target);
|
||||||
if (monster) {
|
if (monster) {
|
||||||
std::string str = "Attacking ";
|
std::string str = "Attacking ";
|
||||||
str.append(monster->name);
|
str.append(monster->name);
|
||||||
|
|
||||||
std::cout << str << std::endl;
|
interact(current_target, 1);
|
||||||
|
|
||||||
interact(monster->object_id);
|
|
||||||
// neuz.player->attack_target = monster->object_id;
|
|
||||||
|
|
||||||
neuz.show_message(str);
|
neuz.show_message(str);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -747,15 +729,131 @@ void bot_tick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
// Reset current target is not running.
|
client.show_message("Can't find target!", {0xFF, 0, 0});
|
||||||
current_target = 0;
|
}
|
||||||
current_pickup_item = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void before_main_loop() {
|
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() {
|
void after_main_loop() {
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,15 @@ namespace fugg {
|
||||||
void send_motion_packet(const uint32_t &action, unsigned long long param0 = 0, unsigned long long param1 = 0,
|
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;
|
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_move_to(const double &x, const double &y, const double &z) const;
|
||||||
void send_chat_message(const std::string &message) const;
|
void send_chat_message(const std::string &message) const;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
Reference in New Issue