Added mana and fatigue point recovery (along with get_mp(), get_fp(), get_max_mp(), get_max_fp())

This commit is contained in:
Knaapchen 2022-11-21 14:49:09 +01:00
parent 1c9001f582
commit af66bfc82f
6 changed files with 200 additions and 13 deletions

View File

@ -84,7 +84,9 @@ namespace flyff {
Necklace = 501,
Ring = 502,
Refresher = 1400,
VitalDrink = 1401,
Food = 1402,
Pill = 1404
};

View File

@ -21,7 +21,8 @@ namespace flyff {
DEFINE_MEMBER(0, const flyff::String, model);
DEFINE_MEMBER(12, const uint32_t, id);
DEFINE_MEMBER(60, const uint32_t, heal_hp);
DEFINE_MEMBER(60, const uint32_t, recovery);
DEFINE_MEMBER(96, const uint32_t, effective_up_to);
// Has to be bigger that 0 to be considered for cooldown.
DEFINE_MEMBER(112, const int32_t, cooldown_time);
@ -52,6 +53,32 @@ namespace flyff {
return false;
}
bool is_refresher() const {
static const uint32_t RECOVERY_SUB_CATEGORY_START = 1400;
if (item_kind2 == ItemKind2::Recovery) {
const uint32_t cd = static_cast<uint32_t>(item_kind3) - RECOVERY_SUB_CATEGORY_START;
if (cd < 5) {
return RECOVERY_COOLDOWN_INDEX[cd] == COOLDOWN_REFRESHER;
}
}
return false;
}
bool is_vitaldrink() const {
static const uint32_t RECOVERY_SUB_CATEGORY_START = 1400;
if (item_kind2 == ItemKind2::Recovery) {
const uint32_t cd = static_cast<uint32_t>(item_kind3) - RECOVERY_SUB_CATEGORY_START;
if (cd < 5) {
return RECOVERY_COOLDOWN_INDEX[cd] == COOLDOWN_VITALDRINK;
}
}
return false;
}
bool is_quest() const { return item_kind2 == ItemKind2::Quest; }
};

View File

@ -66,6 +66,7 @@ namespace flyff {
DEFINE_MEMBER(144, const u32, get_max_origin_hp);
DEFINE_MEMBER(148, const u32, get_max_origin_mp);
DEFINE_MEMBER(152, const u32, get_max_origin_fp);
const MinimumSize<220> _size;
};
@ -154,6 +155,7 @@ namespace flyff {
DEFINE_MEMBER(880, const uint32_t, locked_inventory_slots);
DEFINE_MEMBER(904, uint32_t, if_not_null_needsattackitem);
DEFINE_MEMBER(908, uint32_t, fatiguepoints);
DEFINE_MEMBER(920, ParameterValue, adjusted_parameters[MAX_PARAM]);
DEFINE_MEMBER(1248, ParameterValue, changed_parameters[MAX_PARAM]);
@ -183,6 +185,7 @@ namespace flyff {
DEFINE_MEMBER(1820, uint32_t, server_tick);
DEFINE_MEMBER(1840, int, hitpoints);
DEFINE_MEMBER(1844, int, manapoints);
DEFINE_MEMBER(1848, int, is_grounded);
@ -247,9 +250,6 @@ namespace flyff {
ParameterValue get_change_param(ParamID index) const;
uint32_t get_hp() const {
return raw::get_hitpoint(kMemory.to_inside(this));
}
flyff::Pointer<flyff::ItemProperty> get_equipped_item(const flyff::Part &part) const {
using Fn = FunctionPointer<u32, u32, u32>;
@ -273,6 +273,18 @@ namespace flyff {
return src_speed <= 0 ? 0 : src_speed;
}
uint32_t get_hp() const {
return hitpoints ^ adj_param;
}
uint32_t get_mp() const {
return manapoints ^ adj_param;
}
uint32_t get_fp() const {
return fatiguepoints;
}
uint32_t get_max_hp() const {
float factor = 1.0f;
auto result = get_param(ParamID::MaxHitPoint, get_max_origin_hp());
@ -284,6 +296,28 @@ namespace flyff {
return result;
}
uint32_t get_max_mp() const {
float factor = 1.0f;
auto result = get_param(ParamID::MaxManaPoint, get_max_origin_mp());
auto percent = get_param(ParamID::MaxManaPointScaling, 0);
factor += static_cast<float>(percent) / 100.f;
result = static_cast<float>(result) * factor;
return result;
}
uint32_t get_max_fp() const {
float factor = 1.0f;
auto result = get_param(ParamID::MaxFatiguePoint, get_max_origin_fp());
auto percent = get_param(ParamID::MaxFatiguePointScaling, 0);
factor += static_cast<float>(percent) / 100.f;
result = static_cast<float>(result) * factor;
return result;
}
uint32_t get_hp_percent(int percent = 100) const {
auto max = get_max_hp();
if (max == 0) return 0;
@ -291,6 +325,20 @@ namespace flyff {
return get_hp() * percent / max;
}
uint32_t get_mp_percent(int percent = 100) const {
auto max = get_max_mp();
if (max == 0) return 0;
return get_mp() * percent / max;
}
uint32_t get_fp_percent(int percent = 100) const {
auto max = get_max_fp();
if (max == 0) return 0;
return get_fp() * percent / max;
}
uint32_t get_max_origin_hp() const {
using Fn = FunctionPointer<u32, u32, u32, u32>;
const auto &fn = fugg::function_ref<Fn>(vtable->get_max_origin_hp);
@ -298,6 +346,20 @@ namespace flyff {
return fn(kMemory.to_inside(this), 0, 0);
}
uint32_t get_max_origin_mp() const {
using Fn = FunctionPointer<u32, u32, u32, u32>;
const auto &fn = fugg::function_ref<Fn>(vtable->get_max_origin_mp);
return fn(kMemory.to_inside(this), 0, 0);
}
uint32_t get_max_origin_fp() const {
using Fn = FunctionPointer<u32, u32, u32, u32>;
const auto &fn = fugg::function_ref<Fn>(vtable->get_max_origin_fp);
return fn(kMemory.to_inside(this), 0, 0);
}
float get_attack_range(const AttackRange& range) const {
static const float attack_ranges[] = {
2, 3, 4, 10, 15, 6, 18

View File

@ -22,8 +22,15 @@ namespace flyff {
AdditionalDamage = 35,
// DST_HP_MAX
MaxHitPoint = 44,
// DST_MP_MAX
MaxManaPoint,
// DST_FP_MAX
MaxFatiguePoint,
// DST_HP_MAX_RATE
MaxHitPointScaling = 53,
MaxManaPointScaling,
MaxFatiguePointScaling,
// Max = 82,
};

View File

@ -4,8 +4,13 @@
namespace flyff {
enum class SkillID : uint32_t {
// Assist skills
/* Mercenary */
SwordMastery = 7,
Protect = 9,
BlazingSword = 108,
EmpowerWeapon = 111,
HeartOfFury = 404,
/* Assist */
Haste = 20,
Heal = 44,
Resurrection = 45,
@ -27,7 +32,7 @@ namespace flyff {
static std::ostream &operator<<(std::ostream &os, const SkillID &type) {
os << static_cast<uint32_t>(type);
os << "SkillID(" << static_cast<uint32_t>(type) << ")";
return os;
}
}; // namespace flyff

View File

@ -472,6 +472,15 @@ void on_keyup_hook(int event_type, const EmscriptenKeyboardEvent *event, void *u
}
}
std::cout << "Player has the following " << client.player->skills->size() << " skills" << std::endl;
for(const auto& skill : client.player->skills) {
const auto& property = fugg::Client::get_skill_property(skill.id);
if(property) {
std::cout << client.get_text(property->name) << " ";
}
std::cout << "(" << skill.id << ") at level " << skill.level << std::endl;
}
}
}
}
@ -642,7 +651,7 @@ void attacker_script() {
auto hp = client.player->get_hp();
auto max_hp = client.player->get_max_hp();
// How much HP is left over after healing with this item.
int32_t difference = max_hp - (hp + item_property->heal_hp);
int32_t difference = max_hp - (hp + item_property->recovery);
if (difference >= 0 && std::abs(difference) < std::abs(smallest_difference)) {
food_item = flyff::Pointer<flyff::InventoryItem>(&items[i]);
@ -673,7 +682,7 @@ void attacker_script() {
auto hp = client.player->get_hp();
auto max_hp = client.player->get_max_hp();
// How much HP is left over after healing with this item.
int32_t difference = max_hp - (hp + item_property->heal_hp);
int32_t difference = max_hp - (hp + item_property->recovery);
if (difference >= 0 && std::abs(difference) < std::abs(smallest_difference)) {
pill_item = flyff::Pointer<flyff::InventoryItem>(&items[i]);
@ -688,12 +697,76 @@ void attacker_script() {
str.append(neuz.get_text(pill_item->property->name));
str.append(" because food item was not ready.");
neuz.show_message(str);
neuz.show_message(str, {0x7F, 0, 0});
client.send_use_item_in_inventory(pill_item->index);
}
}
}
if (neuz.player->get_mp_percent() != 100) {
auto mana_item = flyff::Pointer<flyff::InventoryItem>(nullptr);
auto items = player->inventory.begin();
int32_t smallest_difference = std::numeric_limits<int32_t>::max();
for (auto i = 0; i < player->get_inventory_slots(); i++) {
const auto &item_property = items[i].property;
if (item_property &&
player->can_use_item(item_property) &&
item_property->is_refresher()) {
auto mp = client.player->get_mp();
auto max_mp = client.player->get_max_mp();
// How much HP is left over after healing with this item.
int32_t difference = max_mp - (mp + item_property->recovery);
if (difference >= 0 && std::abs(difference) < std::abs(smallest_difference)) {
mana_item = flyff::Pointer<flyff::InventoryItem>(&items[i]);
smallest_difference = difference;
}
}
}
if (mana_item) {
std::string str = "Using ";
str.append(neuz.get_text(mana_item->property->name));
neuz.show_message(str, {0, 0, 0x7F});
client.send_use_item_in_inventory(mana_item->index);
}
}
std::cout << "Player has " << neuz.player->get_mp() << " / " << neuz.player->get_max_mp() << " MP" << std::endl;
std::cout << "Player has " << neuz.player->get_fp() << " / " << neuz.player->get_max_fp() << " FP" << std::endl;
if (neuz.player->get_fp_percent() != 100) {
auto fatigue_item = flyff::Pointer<flyff::InventoryItem>(nullptr);
auto items = player->inventory.begin();
int32_t smallest_difference = std::numeric_limits<int32_t>::max();
for (auto i = 0; i < player->get_inventory_slots(); i++) {
const auto &item_property = items[i].property;
if (item_property &&
player->can_use_item(item_property) &&
item_property->is_vitaldrink()) {
auto fp = client.player->get_fp();
auto max_fp = client.player->get_max_fp();
// How much HP is left over after healing with this item.
int32_t difference = max_fp - (fp + item_property->recovery);
if (difference >= 0 && std::abs(difference) < std::abs(smallest_difference)) {
fatigue_item = flyff::Pointer<flyff::InventoryItem>(&items[i]);
smallest_difference = difference;
}
}
}
if (fatigue_item) {
std::string str = "Drinking ";
str.append(neuz.get_text(fatigue_item->property->name));
neuz.show_message(str, {0, 0x7F, 0});
client.send_use_item_in_inventory(fatigue_item->index);
}
}
// Check if my current target is being attacked by another player.
{
@ -701,7 +774,9 @@ void attacker_script() {
if (monster && !monster->enemies->empty()) {
auto is_player_monster_enemy =
std::find_if(monster->enemies.begin(), monster->enemies.end(),
[&client](const flyff::Mover::HitInfo &x) { return x.object_id == client.player->object_id; }) !=
[&client](const flyff::Mover::HitInfo &x) {
return x.object_id == client.player->object_id;
}) !=
monster->enemies.end();
// If the player is not in the list of enemies, we can not attack the monster.
if (!is_player_monster_enemy) {
@ -788,7 +863,16 @@ void attacker_script() {
client.send_use_skill(flyff::SkillID::Asmodeus);
return;
}
// }
} else if(neuz.player->get_job() == flyff::JobID::Knight) {
const auto &off_hand = player->get_equipped_item(flyff::Part::Shield);
if (off_hand && off_hand->item_kind3 == flyff::ItemKind3::Shield) {
// Only check for the buff if player is wearing a shield.
if (!check_rebuff(neuz.player, neuz.player, {flyff::SkillID::HeartOfFury}).empty()) {
client.send_use_skill(flyff::SkillID::HeartOfFury);
return;
}
}
}
if (item && !item->is_despawned && neuz.player->move_toward_target == 0) {