#include "stat.h" const String Stat::STAT_BINDING_STRING = "Health,Speed,Mana,GCD,Haste,Agility,Strength,Stamina,Intellect,Luck,Haste Rating,Resilience,Armor,Attack Power,Spell Power,Melee Crit,Melee Crit bonus,Spell Crit,Spell Crit Bonus,Block,Parry,Damage Reduction,Melee Damage Reduction,Spell Damage Reduction,Damage Taken,Heal Taken,Melee Damage,Spell Damage,Holy Resist,Shadow Resist,Nature Resist,Fire Resist,Frost Resist,Lightning Resist,Chaos Resist,Silence Resist,Fear Resist,None"; const String Stat::MODIFIER_APPLY_TYPE_BINDING_STRING = "Standard,Only min modifier,Only Max modifier"; _FORCE_INLINE_ Vector > *Stat::get_modifiers() { return &_modifiers; } int Stat::get_modifier_count() { return _modifiers.size(); } Ref Stat::get_modifier(int index) { return _modifiers.get(index); } void Stat::set_dependency(Ref other, Ref curve) { _dependency = other; _dependency_curve = curve; } void Stat::remove_dependencies() { _dependency = Ref(NULL); _dependency_curve = Ref(NULL); } Stat::StatId Stat::get_id() { return _id; } void Stat::set_id(Stat::StatId id) { _id = id; } Stat::StatModifierApplyType Stat::get_stat_modifier_type() { return _modifier_apply_type; } void Stat::set_stat_modifier_type(Stat::StatModifierApplyType value) { _modifier_apply_type = value; } bool Stat::get_locked() { return _locked; } void Stat::set_locked(bool value) { _locked = value; } bool Stat::get_dirty() { return _dirty; } void Stat::set_dirty(bool value) { _dirty = value; } void Stat::add_modifier(int id, float base_mod, float bonus_mod, float percent_mod, bool apply) { Ref statModifier = Ref(memnew(StatModifier(id, base_mod, bonus_mod, percent_mod))); if (apply) { apply_modifier(statModifier); } _modifiers.push_back(statModifier); } void Stat::remove_modifier(int id, bool apply) { for (int i = 0; i < _modifiers.size(); i += 1) { if (_modifiers.get(i)->get_id() == id) { Ref modifier = _modifiers.get(i); _modifiers.remove(i); if (apply) { de_apply_modifier(modifier); } return; } } } void Stat::apply_modifier(Ref modifier) { if (_modifier_apply_type == MODIFIER_APPLY_TYPE_STANDARD) { _base += modifier->get_base_mod(); _bonus += modifier->get_bonus_mod(); _percent += modifier->get_percent_mod(); } else { if (modifier->get_percent_mod() >= (float)0) { _base += modifier->get_base_mod(); _bonus += modifier->get_bonus_mod(); _percent += modifier->get_percent_mod(); } else { int num = -1; if (get_modifiers()->size() > 0) { float percent_mod = get_modifiers()->get(0)->get_percent_mod(); for (int i = 1; i < get_modifiers()->size(); i += 1) { if ((_modifiers.get(i)->get_percent_mod() < (float)0) && (_modifiers.get(i)->get_percent_mod() < percent_mod)) { num = i; percent_mod = _modifiers.get(i)->get_percent_mod(); } } } if (num != -1) { if (modifier->get_percent_mod() < _modifiers.get(num)->get_percent_mod()) { _percent -= _modifiers.get(num)->get_percent_mod(); } _percent += modifier->get_percent_mod(); } else { _percent += modifier->get_percent_mod(); } } } recalculate(); emit_signal("s_changed", Ref(this)); send(); // emit_signal("s_changed", Ref(this)); } void Stat::de_apply_modifier(Ref modifier) { if (_modifier_apply_type == MODIFIER_APPLY_TYPE_STANDARD) { _base -= modifier->get_base_mod(); _bonus -= modifier->get_bonus_mod(); _percent -= modifier->get_percent_mod(); } else { if (modifier->get_percent_mod() >= (float)0) { _base -= modifier->get_base_mod(); _bonus -= modifier->get_bonus_mod(); _percent -= modifier->get_percent_mod(); } else { int num = -1; if (get_modifiers()->size() > 0) { float percent_mod = get_modifiers()->get(0)->get_percent_mod(); for (int i = 1; i < get_modifiers()->size(); i += 1) { if ((_modifiers.get(i)->get_percent_mod() < (float)0) && (_modifiers.get(i)->get_percent_mod() < percent_mod)) { num = i; percent_mod = _modifiers.get(i)->get_percent_mod(); } } } if (num != -1 && _modifiers[num] == modifier) { _percent -= modifier->get_percent_mod(); } } } recalculate(); emit_signal("s_changed", Ref(this)); send(); // emit_signal("s_changed", Ref(this)); } void Stat::re_apply_modifiers() { reset_values(); if (_modifier_apply_type == MODIFIER_APPLY_TYPE_STANDARD) { for (int i = 0; i < _modifiers.size(); i += 1) { Ref mod = _modifiers.get(i); _base += mod->get_base_mod(); _bonus += mod->get_bonus_mod(); _percent += mod->get_percent_mod(); } } else { re_apply_modifier_not_negative_stacking_percents(); } recalculate(); emit_signal("s_changed", Ref(this)); send(); // emit_signal("s_changed", Ref(this)); } void Stat::re_apply_modifier_not_negative_stacking_percents() { reset_values(); for (int i = 1; i < get_modifiers()->size(); i += 1) { if (_modifiers.get(i)->get_percent_mod() > (float)0) { Ref mod = _modifiers.get(i); _base += mod->get_base_mod(); _bonus += mod->get_bonus_mod(); _percent += mod->get_percent_mod(); } } int num = -1; if (get_modifiers()->size() > 0) { float percent_mod = get_modifiers()->get(0)->get_percent_mod(); for (int j = 1; j < get_modifiers()->size(); ++j) { if ((_modifiers.get(j)->get_percent_mod() < (float)0) && (_modifiers.get(j)->get_percent_mod() < percent_mod)) { num = j; percent_mod = _modifiers.get(j)->get_percent_mod(); } } } if (num != -1) { Ref mod = _modifiers.get(num); _base += mod->get_base_mod(); _bonus += mod->get_bonus_mod(); _percent += mod->get_percent_mod(); } recalculate(); emit_signal("s_changed", Ref(this)); send(); // emit_signal("s_changed", Ref(this)); } //Stat float Stat::gets_current() { return _s_current; } void Stat::sets_current(float value) { if (_locked) { return; } _s_current = value; emit_signal("s_changed", Ref(this)); send(); } float Stat::gets_max() { return _s_max; } void Stat::sets_max(float value) { _s_max = value; emit_signal("s_changed", Ref(this)); send(); } float Stat::getc_current() { return _c_current; } void Stat::setc_current(float value) { _c_current = value; emit_signal("c_changed", Ref(this)); } float Stat::getc_max() { return _c_max; } void Stat::setc_max(float value) { _s_current = value; emit_signal("c_changed", Ref(this)); } float Stat::get_base() { return _base; } void Stat::set_base(float value) { _base = value; recalculate(); emit_signal("s_changed", Ref(this)); send(); } float Stat::get_bonus() { return _bonus; } void Stat::set_bonus(float value) { _bonus = value; recalculate(); emit_signal("s_changed", Ref(this)); send(); } float Stat::get_percent() { return _percent; } void Stat::set_percent(float value) { _percent = value; recalculate(); emit_signal("s_changed", Ref(this)); send(); } void Stat::reset_values() { _percent = 100; _bonus = 0; _percent = 0; _dirty = true; emit_signal("s_changed", Ref(this)); send(); } void Stat::recalculate() { float diff = _s_current / _s_max; _s_max = (_base + _bonus) * (_percent / 100.0); if (_s_current > _s_max) { _s_current = _s_max; } _s_current = _s_max * diff; _dirty = true; } void Stat::send() { _c_current = _s_current; _c_max = _s_max; emit_signal("c_changed", Ref(this)); } bool Stat::iss_current_zero() { return (fabs(_s_current) < .000001); } bool Stat::isc_current_zero() { return (fabs(_c_current) < .000001); } void Stat::set_to_max() { _s_current = _s_max; emit_signal("s_changed", Ref(this)); send(); } void Stat::set_values(float base, float bonus, float percent) { _base = base; _bonus = bonus; _percent = percent; recalculate(); emit_signal("s_changed", Ref(this)); send(); } void Stat::set_from_stat(Ref other) { _s_current = other->_s_current; _s_max = other->_s_max; _c_current = other->_c_current; _c_max = other->_c_max; _base = other->_base; _bonus = other->_bonus; _percent = other->_percent; set_dirty(true); emit_signal("s_changed", Ref(this)); send(); } void Stat::set(float current, float max, float base, float bonus, float percent) { _s_current = current; _s_max = max; _c_current = current; _c_max = max; _base = base; _bonus = bonus; _percent = percent; _dirty = true; emit_signal("s_changed", Ref(this)); send(); } Dictionary Stat::to_dict() { return call("_to_dict"); } void Stat::from_dict(const Dictionary &dict) { call("_from_dict", dict); } Dictionary Stat::_to_dict() { Dictionary dict; dict["id"] = _id; dict["modifier_apply_type"] = _modifier_apply_type; dict["locked"] = _locked; dict["dirty"] = _dirty; dict["base"] = _base; dict["bonus"] = _bonus; dict["percent"] = _percent; dict["current"] = _s_current; dict["max"] = _s_max; Dictionary modifiers; for (int i = 0; _modifiers.size(); ++i) { modifiers[i] = _modifiers.get(i)->to_dict(); } dict["modifiers"] = modifiers; return dict; } void Stat::_from_dict(const Dictionary &dict) { ERR_FAIL_COND(dict.empty()); } Stat::Stat() { _id = Stat::STAT_ID_NONE; _locked = false; _base = (float)(0); _bonus = (float)(0); _percent = (float)(0); _s_max = (float)(0); _s_current = (float)(0); _c_max = (float)(0); _c_current = (float)(0); _modifier_apply_type = MODIFIER_APPLY_TYPE_STANDARD; } Stat::Stat(Stat::StatId id) { _id = id; _locked = false; _base = (float)(0); _bonus = (float)(0); _percent = (float)(0); _s_max = (float)(0); _s_current = (float)(0); _c_max = (float)(0); _c_current = (float)(0); _modifier_apply_type = MODIFIER_APPLY_TYPE_STANDARD; } Stat::Stat(Stat::StatId id, StatModifierApplyType modifier_apply_type) { _id = id; _locked = false; _base = (float)(0); _bonus = (float)(0); _percent = (float)(0); _s_max = (float)(0); _s_current = (float)(0); _c_max = (float)(0); _c_current = (float)(0); _modifier_apply_type = modifier_apply_type; _id = id; } //Stat Stat::Stat(Stat::StatId id, StatModifierApplyType modifier_apply_type, float base, float bonus, float percent) { _id = id; _locked = false; _base = (float)(0); _bonus = (float)(0); _percent = (float)(0); _s_max = (float)(0); _s_current = (float)(0); _c_max = (float)(0); _c_current = (float)(0); _modifier_apply_type = modifier_apply_type; _id = id; _base = base; _bonus = bonus; _percent = percent; } Stat::Stat(Stat::StatId id, StatModifierApplyType modifier_apply_type, float base) { _id = id; _locked = false; _base = (float)(0); _bonus = (float)(0); _percent = (float)(0); _s_max = (float)(0); _s_current = (float)(0); _c_max = (float)(0); _c_current = (float)(0); _modifier_apply_type = modifier_apply_type; _id = id; _base = base; _percent = 100; _bonus = 0; } Stat::~Stat() { _modifiers.clear(); } void Stat::_bind_methods() { ADD_SIGNAL(MethodInfo("s_changed", PropertyInfo(Variant::OBJECT, "stat", PROPERTY_HINT_RESOURCE_TYPE, "Stat"))); ADD_SIGNAL(MethodInfo("c_changed", PropertyInfo(Variant::OBJECT, "stat", PROPERTY_HINT_RESOURCE_TYPE, "Stat"))); ClassDB::bind_method(D_METHOD("get_id"), &Stat::get_id); ClassDB::bind_method(D_METHOD("set_id", "id"), &Stat::set_id); //ADD_PROPERTY(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_ENUM, STAT_BINDING_STRING), "set_id", "get_id"); ClassDB::bind_method(D_METHOD("get_stat_modifier_type"), &Stat::get_stat_modifier_type); ClassDB::bind_method(D_METHOD("set_stat_modifier_type", "value"), &Stat::set_stat_modifier_type); ADD_PROPERTY(PropertyInfo(Variant::INT, "stat_type", PROPERTY_HINT_ENUM, "Standard, Min Modifier, Max modifier"), "set_stat_modifier_type", "get_stat_modifier_type"); ClassDB::bind_method(D_METHOD("get_locked"), &Stat::get_locked); ClassDB::bind_method(D_METHOD("set_locked", "value"), &Stat::set_locked); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "locked"), "set_locked", "get_locked"); ClassDB::bind_method(D_METHOD("get_dirty"), &Stat::get_dirty); ClassDB::bind_method(D_METHOD("set_dirty", "value"), &Stat::set_dirty); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_dirty"), "set_dirty", "get_dirty"); ClassDB::bind_method(D_METHOD("gets_current"), &Stat::gets_current); ClassDB::bind_method(D_METHOD("sets_current", "value"), &Stat::sets_current); ADD_PROPERTY(PropertyInfo(Variant::REAL, "scurrent"), "sets_current", "gets_current"); ClassDB::bind_method(D_METHOD("getc_current"), &Stat::getc_current); ClassDB::bind_method(D_METHOD("setc_current", "value"), &Stat::setc_current); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ccurrent"), "setc_current", "getc_current"); ClassDB::bind_method(D_METHOD("gets_max"), &Stat::gets_max); ClassDB::bind_method(D_METHOD("sets_max"), &Stat::sets_max); ADD_PROPERTY(PropertyInfo(Variant::REAL, "smax"), "sets_max", "gets_max"); ClassDB::bind_method(D_METHOD("getc_max"), &Stat::getc_max); ClassDB::bind_method(D_METHOD("setc_max"), &Stat::setc_max); ADD_PROPERTY(PropertyInfo(Variant::REAL, "cmax"), "setc_max", "getc_max"); ClassDB::bind_method(D_METHOD("get_base"), &Stat::get_base); ClassDB::bind_method(D_METHOD("set_base", "value"), &Stat::set_base); ADD_PROPERTY(PropertyInfo(Variant::REAL, "base"), "set_base", "get_base"); ClassDB::bind_method(D_METHOD("get_bonus"), &Stat::get_bonus); ClassDB::bind_method(D_METHOD("set_bonus", "value"), &Stat::set_bonus); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bonus"), "set_bonus", "get_bonus"); ClassDB::bind_method(D_METHOD("get_percent"), &Stat::get_percent); ClassDB::bind_method(D_METHOD("set_percent", "value"), &Stat::set_percent); ADD_PROPERTY(PropertyInfo(Variant::REAL, "percent"), "set_percent", "get_percent"); ClassDB::bind_method(D_METHOD("reset_values"), &Stat::reset_values); ClassDB::bind_method(D_METHOD("recalculate"), &Stat::recalculate); ClassDB::bind_method(D_METHOD("iss_current_zero"), &Stat::iss_current_zero); ClassDB::bind_method(D_METHOD("isc_current_zero"), &Stat::isc_current_zero); ClassDB::bind_method(D_METHOD("set_from_stat", "stat"), &Stat::set_from_stat); //ClassDB::bind_method(D_METHOD("set", "current", "max", "modCurrent", "modMax", "modPercent", "nomodCurrent", "nomodMax", "nomodPercent"), &Stat::set); //ClassDB::bind_method(D_METHOD("set_from_stat", "stat"), &Stat::set_from_stat); //ClassDB::bind_method(D_METHOD("copy_values_from", "stat"), &Stat::copy_values_from); ClassDB::bind_method(D_METHOD("set_to_max"), &Stat::set_to_max); ClassDB::bind_method(D_METHOD("set_values", "current", "base", "percent"), &Stat::set_values); //ClassDB::bind_method(D_METHOD("apply_modifier", "modifier"), &Stat::apply_modifier); //ClassDB::bind_method(D_METHOD("de_apply_modifier", "modifier"), &Stat::de_apply_modifier); ClassDB::bind_method(D_METHOD("re_apply_modifier_not_negative_stacking_percents"), &Stat::re_apply_modifier_not_negative_stacking_percents); ClassDB::bind_method(D_METHOD("add_modifier", "id", "base_mod", "bonus_mod", "percent_mod", "apply"), &Stat::add_modifier); ClassDB::bind_method(D_METHOD("remove_modifier", "id", "apply"), &Stat::remove_modifier); ClassDB::bind_method(D_METHOD("re_apply_modifiers"), &Stat::re_apply_modifiers); ClassDB::bind_method(D_METHOD("set_dependency", "stat", "curve"), &Stat::set_dependency); ClassDB::bind_method(D_METHOD("remove_dependencies"), &Stat::remove_dependencies); //Serialization BIND_VMETHOD(MethodInfo("_from_dict", PropertyInfo(Variant::DICTIONARY, "dict"))); BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::DICTIONARY, "dict"), "_to_dict")); ClassDB::bind_method(D_METHOD("from_dict", "dict"), &Stat::from_dict); ClassDB::bind_method(D_METHOD("to_dict"), &Stat::to_dict); ClassDB::bind_method(D_METHOD("_from_dict", "dict"), &Stat::_from_dict); ClassDB::bind_method(D_METHOD("_to_dict"), &Stat::_to_dict); BIND_ENUM_CONSTANT(Stat::STAT_ID_HEALTH); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPEED); BIND_ENUM_CONSTANT(Stat::STAT_ID_MANA); BIND_ENUM_CONSTANT(Stat::STAT_ID_GLOBAL_COOLDOWN); BIND_ENUM_CONSTANT(Stat::STAT_ID_HASTE); BIND_ENUM_CONSTANT(Stat::STAT_ID_AGILITY); BIND_ENUM_CONSTANT(Stat::STAT_ID_STRENGTH); BIND_ENUM_CONSTANT(Stat::STAT_ID_STAMINA); BIND_ENUM_CONSTANT(Stat::STAT_ID_INTELLECT); BIND_ENUM_CONSTANT(Stat::STAT_ID_LUCK); BIND_ENUM_CONSTANT(Stat::STAT_ID_HASTE_RATING); BIND_ENUM_CONSTANT(Stat::STAT_ID_RESLILIENCE); BIND_ENUM_CONSTANT(Stat::STAT_ID_ARMOR); BIND_ENUM_CONSTANT(Stat::STAT_ID_ATTACK_POWER); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPELL_POWER); BIND_ENUM_CONSTANT(Stat::STAT_ID_MELEE_CRIT); BIND_ENUM_CONSTANT(Stat::STAT_ID_MELEE_CRIT_BONUS); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPELL_CRIT); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPELL_CRIT_BONUS); BIND_ENUM_CONSTANT(Stat::STAT_ID_BLOCK); BIND_ENUM_CONSTANT(Stat::STAT_ID_PARRY); BIND_ENUM_CONSTANT(Stat::STAT_ID_DAMAGE_REDUCTION); BIND_ENUM_CONSTANT(Stat::STAT_ID_MELEE_DAMAGE_REDUCTION); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPELL_DAMAGE_REDUCTION); BIND_ENUM_CONSTANT(Stat::STAT_ID_DAMAGE_TAKEN); BIND_ENUM_CONSTANT(Stat::STAT_ID_MELEE_DAMAGE); BIND_ENUM_CONSTANT(Stat::STAT_ID_SPELL_DAMAGE); BIND_ENUM_CONSTANT(Stat::STAT_ID_HOLY_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_SHADOW_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_NATURE_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_FIRE_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_FROST_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_LIGHTNING_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_CHAOS_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_SILENCE_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_FEAR_RESIST); BIND_ENUM_CONSTANT(Stat::STAT_ID_TOTAL_STATS); BIND_ENUM_CONSTANT(Stat::STAT_ID_NONE); BIND_ENUM_CONSTANT(Stat::MODIFIER_APPLY_TYPE_STANDARD); BIND_ENUM_CONSTANT(Stat::MODIFIER_APPLY_TYPE_ONLY_MIN_MODIFIER); BIND_ENUM_CONSTANT(Stat::MODIFIER_APPLY_TYPE_ONLY_MAX_MODIFIER); }