#pragma once #include #include #include #include #include #include "core.h" #include "item/ItemProperty.h" #include "math.h" #include "object/Object.h" #include "object/ObjectProperty.h" #include "object/ObjectType.h" #include "skill/Skill.h" #include "item/InventoryItem.h" #include "item/Part.h" namespace flyff { namespace raw { extern "C" { // w2c_f410: CMover::GetHitPoint(PlayerObject* mover); extern u32 w2c_f411(u32); // w2c_f2454: CCooltimeMgr::CanUse(uint64_t* timers, ItemProperty* prop); extern u32 w2c_f2466(u32, u32); } }; struct __attribute__((packed)) Mover { static constexpr uint32_t MAX_PARAM = 0x52; 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; struct __attribute__((packed)) Vtable { union { DEFINE_MEMBER(52, const u32, get_level); DEFINE_MEMBER(56, const u32, get_gender); DEFINE_MEMBER(96, const u32, get_active_hand_item_prop); DEFINE_MEMBER(144, const u32, get_max_origin_hp); DEFINE_MEMBER(148, const u32, get_max_origin_mp); const MinimumSize<220> _size; }; }; struct __attribute__((packed)) Skill { union { DEFINE_MEMBER(0, const flyff::Skill, id); DEFINE_MEMBER(4, const uintptr_t, level); }; }; struct __attribute__((packed)) Buff { enum class Type { Item = 0, Skill = 1, }; struct __attribute__((packed)) Vtable { union { DEFINE_MEMBER(28, const u32, get_type); DEFINE_MEMBER(32, const u32, get_id); }; }; union { DEFINE_MEMBER(0, const Pointer, vtable); DEFINE_MEMBER(4, const Pointer, property); DEFINE_MEMBER(8, const Parameter, param_id); DEFINE_MEMBER(16, const uint64_t, time_instantiated); DEFINE_MEMBER(24, const uint64_t, time_total); DEFINE_MEMBER(32, const int, level); DEFINE_MEMBER(36, const bool, is_removed); DEFINE_MEMBER(37, const bool, is_sfx); }; Type get_type() const { using Fn = FunctionPointer; const auto &fn = fugg::function_ref(vtable->get_type); return fn(kMemory.to_inside(this)); } int get_id() const { using Fn = FunctionPointer; const auto &fn = fugg::function_ref(vtable->get_id); return fn(kMemory.to_inside(this)); } uint64_t get_time_remaining() const; }; union { DEFINE_MEMBER(0x0, const Pointer, vtable); DEFINE_MEMBER(0x18, Matrix4, world_matrix); DEFINE_MEMBER(152, Vector3, position); DEFINE_MEMBER(164, Vector3, rotation); DEFINE_MEMBER(188, Pointer, property); DEFINE_MEMBER(212, int, property_id); DEFINE_MEMBER(216, bool, is_despawned); DEFINE_MEMBER(352, MoverID, object_id); DEFINE_MEMBER(920, Parameter, adjusted_parameters[MAX_PARAM]); DEFINE_MEMBER(1248, Parameter, changed_parameters[MAX_PARAM]); DEFINE_MEMBER(1576, Vector>, buffs); 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); DEFINE_MEMBER(1744, MoverID, selected_target); // The id of the target that it hit last. DEFINE_MEMBER(1752, MoverID, attack_target); DEFINE_MEMBER(1760, MoverID, follow_target); // The id, only non-zero when the attack animation plays, of the target it is attacking. 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(1848, int, is_grounded); DEFINE_MEMBER(1792, int, current_animation); DEFINE_MEMBER(204, ObjectType, type); DEFINE_MEMBER(216, uint32_t, existence_check); DEFINE_MEMBER(1804, uint32_t, object_state); DEFINE_MEMBER(1808, uint32_t, object_state_flags); DEFINE_MEMBER(904, uint32_t, if_not_null_needsattackitem); DEFINE_MEMBER(192, uintptr_t, world); DEFINE_MEMBER(860, Vector, inventory); DEFINE_MEMBER(3324, Timestamp, last_food_time); DEFINE_MEMBER(3348, Timestamp, last_refresher_time); DEFINE_MEMBER(3356, Timestamp, last_vitaldrink_time); DEFINE_MEMBER(3424, Vector, skills); const MinimumSize<4096> size; }; uint32_t get_skill_level(const flyff::Skill &skill_index) const { for (const auto &skill: skills) { if (skill_index == skill.id) return skill.level; } return 0; } bool can_use_item(const Pointer &property) { return raw::w2c_f2466(kMemory.to_inside(&last_food_time), static_cast(property)); } bool is_in_combat() const; 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 adjusted_parameters[index] ^ adj_param ^ 0x0554e725 + index * 0x41c64e6d; } Parameter get_change_param(Parameter index) const { return changed_parameters[index] ^ adj_param ^ index * 0x41c64e6d + 0xb5a52d1a; } u32 get_hp() const { return raw::w2c_f411(kMemory.to_inside(this)); } flyff::Pointer get_equipped_item(const flyff::Part &part) { using Fn = FunctionPointer; const auto &fn = fugg::function_ref(vtable->get_active_hand_item_prop); const auto &ptr = fn(kMemory.to_inside(this), static_cast(part)); return flyff::Pointer(ptr); } 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); factor += (float) percent / (float) 100; result = static_cast(result) * factor; return result; } uint32_t get_hp_percent(int percent = 100) const { int max = get_max_hp(); if (max == 0) return 0; return get_hp() * percent / max; } uint32_t 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; } uint32_t get_move_state() const { return (object_state & ObjectState::MovementAll); } uint32_t get_turn_state() const { return (object_state & ObjectState::TurnAll); } uint32_t get_look_state() const { return (object_state & ObjectState::LookAll); } uint32_t get_jump_state() const { return (object_state & ObjectState::JumpAll); } uint32_t get_attack_state() const { return (object_state & ObjectState::AtkAll); } uint32_t get_damage_state() const { return (object_state & ObjectState::DmgAll); } uint32_t get_action_state() const { return (object_state & ObjectState::ActionAll); } bool is_fly() const { return (object_state_flags & ObjectStateFlags::Fly) != 0; } bool is_dead() const { return (object_state & ObjectState::DieAll) != 0; } bool is_sit() const { return (object_state_flags & ObjectStateFlags::Sit) != 0; } // Whether the movement state is running, not if the Mover // is actually moving. See `is_moving()` bool is_run() const { return (object_state_flags & ObjectStateFlags::Walk) == 0; } // Whether the movement state is walking, not if the Mover // is actually moving. See `is_moving()` bool is_walk() const { return (object_state_flags & ObjectStateFlags::Walk) != 0; } // Normal action - No other commands have any effect during this action. bool is_action() const { return (object_state & ObjectState::ActionAll) != 0; } bool is_moving() const { return (get_move_state() == ObjectState::MoveForward || get_move_state() == ObjectState::MoveBackward || get_move_state() == ObjectState::Left || get_move_state() == ObjectState::Right); } bool is_jumping() const { return (object_state & ObjectState::JumpAll) != 0; } bool is_attacking() const { return (object_state & ObjectState::AtkAll) != 0; } bool is_damaged() const { return (object_state & ObjectState::DmgAll) != 0; } bool is_turning() const { return (object_state & ObjectState::TurnAll) != 0; } u32 get_level() { const auto &fn = fugg::function_ref>(vtable->get_level); return fn(kMemory.to_inside(this)); } // int32_t get_gender() { // // The function itself works but I fear it returns wrong results. // // Female player = 0 // // Male player = 0 // // Npc = 2 // const auto& fn = fugg::function_ref>>(vtable->get_gender); // return fn(Pointer(this)); // } }; struct MoverMap { struct __attribute__((packed)) Node { const Pointer next; unsigned int list_index; unsigned long long hash; Pointer mover; }; const Pointer buckets; size_t capacity; const Pointer first; }; }; // namespace flyff