/* Copyright (c) 2019-2023 Péter Magyar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "entity.h" #include "../database/ess_resource_db.h" #include "../singletons/ess.h" #include "../singletons/profile_manager.h" #include "../data/species/entity_species_data.h" #include "../data/spells/spell.h" #include "../entities/auras/aura_data.h" #include "../infos/spell_cast_info.h" #include "../inventory/bag.h" #include "../pipelines/spell_damage_info.h" #include "../pipelines/spell_heal_info.h" #include "../profiles/class_profile.h" #include "./data/character_spec.h" #include "./data/entity_data.h" #include "./data/vendor_item_data.h" #include "./data/vendor_item_data_entry.h" #include "./resources/entity_resource_health.h" #include "./resources/entity_resource_speed.h" #include "./skills/entity_skill.h" #include "scene/2d/node_2d.h" #include "core/object/script_language.h" #include "../defines.h" #define PROPERTY_DEBUG false #if PROPERTY_DEBUG #define PROPERTY_USAGE_ENTITY_HIDDEN PROPERTY_USAGE_DEFAULT #else #define PROPERTY_USAGE_ENTITY_HIDDEN PROPERTY_USAGE_STORAGE #endif #define NOTIFICATION_IMPLS(func, signal, ...) \ if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) \ _s_ai->func(this, __VA_ARGS__); \ \ if (has_method("_" #func)) \ call("_" #func, __VA_ARGS__); \ \ for (int i = 0; i < _s_auras.size(); ++i) { \ Ref ad = _s_auras.get(i); \ ad->get_aura()->func(ad, __VA_ARGS__); \ } \ \ emit_signal(signal, this, __VA_ARGS__); #define NOTIFICATION_IMPLSS(func, signal) \ if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) \ _s_ai->func(this); \ \ if (has_method("_" #func)) \ call("_" #func); \ \ for (int i = 0; i < _s_auras.size(); ++i) { \ Ref ad = _s_auras.get(i); \ ad->get_aura()->func(ad); \ } \ \ emit_signal(signal, this); #define NOTIFICATION_IMPLC(func, signal, ...) \ if (has_method("_" #func)) \ call("_" #func, __VA_ARGS__); \ \ for (int i = 0; i < _c_auras.size(); ++i) { \ Ref ad = _c_auras.get(i); \ ad->get_aura()->func(ad, __VA_ARGS__); \ } \ \ emit_signal(signal, this, __VA_ARGS__); #define NOTIFICATION_IMPLCS(func, signal) \ if (has_method("_" #func)) \ call("_" #func); \ \ for (int i = 0; i < _c_auras.size(); ++i) { \ Ref ad = _c_auras.get(i); \ ad->get_aura()->func(ad); \ } \ \ emit_signal(signal, this); #define NOTIFICATION_RES_IMPLS(func, signal, ...) \ if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) \ _s_ai->func(__VA_ARGS__); \ \ if (has_method("_" #func)) \ call("_" #func, __VA_ARGS__); \ \ for (int i = 0; i < _s_auras.size(); ++i) { \ Ref ad = _s_auras.get(i); \ ad->get_aura()->func(ad, __VA_ARGS__); \ } \ \ emit_signal(signal, __VA_ARGS__); #define NOTIFICATION_RES_IMPLC(func, signal, ...) \ if (has_method("_" #func)) \ call("_" #func, __VA_ARGS__); \ \ for (int i = 0; i < _c_auras.size(); ++i) { \ Ref ad = _c_auras.get(i); \ ad->get_aura()->func(ad, __VA_ARGS__); \ } \ \ emit_signal(signal, __VA_ARGS__); #define NOTIFICATION_AURA_IMPLS(func, signal, what, ...) \ if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) \ _s_ai->func(what, __VA_ARGS__); \ \ if (has_method("_" #func)) \ call("_" #func, what, __VA_ARGS__); \ \ for (int i = 0; i < _s_auras.size(); ++i) { \ Ref ad = _s_auras.get(i); \ ad->get_aura()->func(what, ad, __VA_ARGS__); \ } \ \ emit_signal(signal, what, __VA_ARGS__); #define NOTIFICATION_AURA_DIFF_IMPLS(func, aura_func, signal, what, ...) \ if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) \ _s_ai->func(what, __VA_ARGS__); \ \ if (has_method("_" #func)) \ call("_" #func, what, __VA_ARGS__); \ \ for (int i = 0; i < _s_auras.size(); ++i) { \ Ref ad = _s_auras.get(i); \ ad->get_aura()->aura_func(what, ad, __VA_ARGS__); \ } \ \ emit_signal(signal, what, __VA_ARGS__); #define NOTIFICATION_AURA_IMPLC(func, signal, what, ...) \ if (has_method("_" #func)) \ call("_" #func, what, __VA_ARGS__); \ \ for (int i = 0; i < _c_auras.size(); ++i) { \ Ref ad = _c_auras.get(i); \ ad->get_aura()->func(what, ad, __VA_ARGS__); \ } \ \ emit_signal(signal, what, __VA_ARGS__); NodePath Entity::body_get_path() { return _body_path; } void Entity::body_set_path(NodePath value) { _body_path = value; body_set(get_node_or_null(_body_path)); if (ObjectDB::instance_validate(_body)) { _body->set_owner(this); } } Node *Entity::body_get() { return _body; } Spatial *Entity::body_get_3d() { return _body_3d; } Node2D *Entity::body_get_2d() { return _body_2d; } void Entity::body_set(Node *body) { _body = body; _body_2d = Object::cast_to(body); _body_3d = Object::cast_to(body); } void Entity::body_instance(const Ref &data, const int model_index) { call("_body_instance", data, model_index); } void Entity::_body_instance(const Ref &data, const int model_index) { if (is_queued_for_deletion()) { return; } if (body_get() == NULL && data.is_valid() && data->get_entity_species_data().is_valid() && data->get_entity_species_data()->get_model_data_count() > model_index && data->get_entity_species_data()->get_model_data(model_index).is_valid() && data->get_entity_species_data()->get_model_data(model_index)->get_body().is_valid()) { Node *node = data->get_entity_species_data()->get_model_data(model_index)->get_body()->instance(); add_child(node); body_set(node); body_on_changed(); } } void Entity::body_on_changed() { if (has_method("_body_changed")) { call("_body_changed"); } emit_signal("body_changed", this); } NodePath Entity::get_character_skeleton_path() { return _character_skeleton_path; } void Entity::set_character_skeleton_path(NodePath value) { _character_skeleton_path = value; set_character_skeleton(get_node_or_null(_character_skeleton_path)); } Node *Entity::get_character_skeleton() { return _character_skeleton; } void Entity::set_character_skeleton(Node *skeleton) { _character_skeleton = skeleton; if (ObjectDB::instance_validate(_character_skeleton) && _character_skeleton->has_method("add_model_visual")) { for (int i = 0; i < _c_equipment.size(); ++i) { Ref ii = _c_equipment[i]; if (ii.is_valid()) _character_skeleton->call("add_model_visual", ii->get_item_template()->get_model_visual()); } } } //GUID int Entity::gets_guid() { return _s_guid; } void Entity::sets_guid(int value) { _s_guid = value; VRPC(setc_guid, value); } int Entity::getc_guid() { return _c_guid; } void Entity::setc_guid(int value) { _c_guid = value; //set_name(String::num(_c_guid)); } //Transforms Transform Entity::get_transform_3d(bool only_stored) const { if (!only_stored && _body_3d) { ERR_FAIL_COND_V(!ObjectDB::instance_validate(_body_3d), _transform); return _body_3d->get_transform(); } return _transform; } void Entity::set_transform_3d(const Transform &transform, bool only_stored) { if (!only_stored && _body_3d) { ERR_FAIL_COND(!ObjectDB::instance_validate(_body_3d)); return _body_3d->set_transform(transform); } _transform = transform; } Transform2D Entity::get_transform_2d(bool only_stored) const { if (!only_stored && _body_2d) { ERR_FAIL_COND_V(!ObjectDB::instance_validate(_body_2d), _transform_2d); return _body_2d->get_transform(); } return _transform_2d; } void Entity::set_transform_2d(const Transform2D &transform, bool only_stored) { if (!only_stored && _body_2d) { ERR_FAIL_COND(!ObjectDB::instance_validate(_body_2d)); return _body_2d->set_transform(_transform_2d); } _transform_2d = transform; } //EntityPlayerType int Entity::gets_entity_player_type() { return _s_entity_player_type; } void Entity::sets_entity_player_type(int value) { _s_entity_player_type = value; VRPC(setc_entity_player_type, value); } int Entity::getc_entity_player_type() { return _c_entity_player_type; } void Entity::setc_entity_player_type(int value) { _c_entity_player_type = value; } //EntityType int Entity::gets_entity_type() { return _s_entity_type; } void Entity::sets_entity_type(int value) { _s_entity_type = value; VRPC(setc_entity_type, value); } int Entity::getc_entity_type() { return _c_entity_type; } void Entity::setc_entity_type(int value) { _c_entity_type = value; } //Relations EntityEnums::EntityRelationType Entity::gets_relation_to_bind(Node *to) { Entity *e = Object::cast_to(to); ERR_FAIL_COND_V(!ObjectDB::instance_validate(e), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); return gets_relation_to(e); } EntityEnums::EntityRelationType Entity::gets_relation_to(Entity *to) { ERR_FAIL_COND_V(!ObjectDB::instance_validate(to), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); return static_cast(static_cast(call("_gets_relation_to", to))); } EntityEnums::EntityRelationType Entity::_gets_relation_to(Node *to) { if (to == this) { return EntityEnums::ENTITY_RELATION_TYPE_FRIENDLY; } return EntityEnums::ENTITY_RELATION_TYPE_HOSTILE; } EntityEnums::EntityRelationType Entity::getc_relation_to_bind(Node *to) { Entity *e = Object::cast_to(to); ERR_FAIL_COND_V(!ObjectDB::instance_validate(e), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); return getc_relation_to(e); } EntityEnums::EntityRelationType Entity::getc_relation_to(Entity *to) { ERR_FAIL_COND_V(!ObjectDB::instance_validate(to), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); return static_cast(static_cast(call("_getc_relation_to", to))); } EntityEnums::EntityRelationType Entity::_getc_relation_to(Node *to) { if (to == this) { return EntityEnums::ENTITY_RELATION_TYPE_FRIENDLY; } return EntityEnums::ENTITY_RELATION_TYPE_HOSTILE; } //EntityInteractionType EntityEnums::EntityInteractionType Entity::gets_entity_interaction_type() { return _s_interaction_type; } void Entity::sets_entity_interaction_type(EntityEnums::EntityInteractionType value) { _s_interaction_type = value; VRPC(setc_entity_interaction_type, value); } EntityEnums::EntityInteractionType Entity::getc_entity_interaction_type() { return _c_interaction_type; } void Entity::setc_entity_interaction_type(EntityEnums::EntityInteractionType value) { _c_interaction_type = value; } int Entity::gets_immunity_flags() { return _s_immunity_flags; } void Entity::sets_immunity_flags(int value) { _s_immunity_flags = value; } int Entity::gets_entity_flags() { return _s_entity_flags; } void Entity::sets_entity_flags(int value) { _s_entity_flags = value; VRPC(setc_entity_flags, value); } int Entity::getc_entity_flags() { return _c_entity_flags; } void Entity::setc_entity_flags(int value) { _c_entity_flags = value; } String Entity::gets_entity_name() { return _s_entity_name; } void Entity::sets_entity_name(String value) { _s_entity_name = value; emit_signal("sname_changed", this); VRPC(setc_entity_name, value); } String Entity::getc_entity_name() { return _c_entity_name; } void Entity::setc_entity_name(String value) { _c_entity_name = value; emit_signal("cname_changed", this); } int Entity::gets_model_index() { return _s_model_index; } void Entity::sets_model_index(int value) { _s_model_index = value; VRPC(setc_model_index, value); } int Entity::getc_model_index() { return _c_model_index; } void Entity::setc_model_index(int value) { _c_model_index = value; if (ObjectDB::instance_validate(_character_skeleton)) { if (_character_skeleton->has_method("set_model_index")) _character_skeleton->call("set_model_index", _c_model_index); } } int Entity::gets_level() { return _s_level; } void Entity::sets_level(int value) { _s_level = value; emit_signal("son_level_changed", this, value); VRPC(setc_level, value); } int Entity::getc_level() { return _c_level; } void Entity::setc_level(int value) { _c_level = value; emit_signal("con_level_changed", this, value); } int Entity::gets_xp() { return _s_xp; } void Entity::sets_xp(int value) { _s_xp = value; ORPC(setc_xp, value); } int Entity::getc_xp() { return _c_xp; } void Entity::setc_xp(int value) { _c_xp = value; } int Entity::gets_money() { return _s_money; } void Entity::sets_money(int value) { _s_money = value; ORPC(setc_money, value); } int Entity::getc_money() { return _c_money; } void Entity::setc_money(int value) { _c_money = value; } int Entity::gets_entity_data_id() { return _s_class_id; } void Entity::sets_entity_data_id(int value) { _s_class_id = value; } int Entity::getc_entity_data_id() { return _c_class_id; } void Entity::setc_entity_data_id(int value) { _c_class_id = value; if (_c_class_id == 0) { setc_entity_data(Ref()); return; } if (ESS::get_singleton() != NULL) { setc_entity_data(ESS::get_singleton()->get_resource_db()->get_entity_data(_c_class_id)); } } StringName Entity::gets_entity_data_path() { return _s_entity_data_path; } void Entity::sets_entity_data_path(const StringName &value) { _s_entity_data_path = value; } Ref Entity::gets_entity_data() { return _s_entity_data; } void Entity::sets_entity_data(Ref value) { if (is_queued_for_deletion()) { return; } _s_class_id = 0; if (value.is_valid()) { _s_class_id = value->get_id(); } _s_entity_data = value; //setup(); body_instance(value, _s_model_index); emit_signal("sentity_data_changed", value); VRPC(setc_entity_data_id, _s_class_id); } Ref Entity::getc_entity_data() { return _c_entity_data; } void Entity::setc_entity_data(Ref value) { _c_entity_data = value; body_instance(value, _c_model_index); emit_signal("centity_data_changed", value); } EntityEnums::AIStates Entity::gets_ai_state() const { return _sai_state; } void Entity::sets_ai_state(EntityEnums::AIStates state) { _sai_state = state; } EntityEnums::AIStates Entity::gets_ai_state_stored() const { return _sai_state_stored; } void Entity::sets_ai_state_stored(EntityEnums::AIStates state) { _sai_state_stored = state; } int Entity::gets_seed() { return _s_seed; } void Entity::sets_seed(int value) { _s_seed = value; ORPC(setc_seed, value); } int Entity::getc_seed() { return _c_seed; } void Entity::setc_seed(int value) { _c_seed = value; } void Entity::_initialize() { _s_resources.resize(EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN); _c_resources.resize(EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN); _s_resources.set(EntityEnums::ENTITY_RESOURCE_INDEX_HEALTH, Ref(memnew(EntityResourceHealth))); _s_resources.set(EntityEnums::ENTITY_RESOURCE_INDEX_SPEED, Ref(memnew(EntityResourceSpeed))); _c_resources.set(EntityEnums::ENTITY_RESOURCE_INDEX_HEALTH, Ref(memnew(EntityResourceHealth))); _c_resources.set(EntityEnums::ENTITY_RESOURCE_INDEX_SPEED, Ref(memnew(EntityResourceSpeed))); for (int i = 0; i < EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN; ++i) { _s_resources.get(i)->set_owner(this); _c_resources.get(i)->set_owner(this); } } void Entity::setup(Ref info) { ERR_FAIL_COND(!info.is_valid()); sets_guid(info->get_guid()); sets_entity_player_type(info->get_entity_player_type()); if (info->get_network_owner() != 0) { set_network_master(info->get_network_owner()); } sets_original_entity_controller(info->get_entity_controller()); sets_entity_controller(info->get_entity_controller()); _s_level = info->get_level(); _s_xp = info->get_xp(); if (info->get_entity_name() != "") { sets_entity_name(info->get_entity_name()); } if (!info->get_serialized_data().empty()) { from_dict(info->get_serialized_data()); } else { sets_entity_data(info->get_entity_data()); } if (has_method("_setup")) { call_multilevel("_setup"); } } void Entity::_setup() { ERR_FAIL_COND(!ESS::get_singleton()); if (!_s_entity_data.is_valid()) { return; } if (_deserialized) { Ref cc = gets_entity_data()->get_entity_class_data(); ERR_FAIL_COND(!cc.is_valid()); //Ref stat_data = _s_entity_data->get_stat_data(); sets_ai(_s_entity_data->get_ai_instance()); for (int i = 0; i < _s_auras.size(); ++i) { Ref ad = _s_auras.get(i); if (!ad->get_aura()->aura_get_hide()) VRPCOBJ(aura_addc_rpc, JSON::print(ad->to_dict()), aura_addc, ad); } if (gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_PLAYER || gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_DISPLAY) { /* if (ESS::get_singleton()->get_use_global_class_level()) { Ref cp = ProfileManager::get_singleton()->getc_player_profile()->get_class_profile(gets_entity_data()->get_path()); if (cp.is_valid()) { int leveldiff = cp->get_level() - _s_level; sets_class_level(cp->get_level()); if (leveldiff > 0) { levelup_sclass(leveldiff); } sets_class_xp(cp->get_xp()); } } */ setup_actionbars(); } if (gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_AI) { sets_entity_name(_s_entity_data->get_name()); } return; } ERR_FAIL_COND(!gets_entity_data().is_valid()); Ref cc = gets_entity_data()->get_entity_class_data(); ERR_FAIL_COND(!cc.is_valid()); Ref stat_data = cc->get_stat_data(); ERR_FAIL_COND(!stat_data.is_valid()); for (int i = 0; i < _stats.size(); ++i) { stat_set_base(i, stat_data->get_base(i)); } for (int i = 0; i < _stats.size(); ++i) { stat_setc_current(i, stat_gets_current(i)); stat_set_dirty(i, false); } for (int i = 0; i < cc->get_num_auras(); ++i) { Ref a = cc->get_aura(i); if (a.is_valid()) { a->aura_sapply_simple(this, this, 1.0); } } _s_entity_data->setup_resources(this); sets_entity_data_id(_s_entity_data->get_id()); Ref spd = _s_entity_data->get_entity_species_data(); if (spd.is_valid()) { sets_entity_type(spd->get_type()); } else { sets_entity_type(0); } sets_entity_interaction_type(_s_entity_data->get_entity_interaction_type()); sets_immunity_flags(_s_entity_data->get_immunity_flags()); sets_entity_flags(_s_entity_data->get_entity_flags()); //if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_NONE) { // sets_original_entity_controller(_s_entity_data->get_entity_controller()); // sets_entity_controller(_s_entity_data->get_entity_controller()); //} //sets_entity_name(_s_entity_data->get_entity_name()); sets_money(_s_entity_data->get_money()); Ref cd = _s_entity_data->get_entity_class_data(); if (cd.is_valid()) { for (int i = 0; i < cd->get_num_start_spells(); ++i) { spell_adds(cd->get_start_spell(i)); } } for (int i = 0; i < cc->get_num_craft_recipes(); ++i) { craft_adds_recipe(cc->get_craft_recipe(i)); } if (_s_entity_data->get_equipment_data().is_valid()) { Ref eqd = _s_entity_data->get_equipment_data(); for (int i = 0; i < _s_equipment.size(); ++i) { Ref ii = eqd->get_item(i); if (ii.is_valid()) _s_equipment.write[i] = ii; } } sets_ai(_s_entity_data->get_ai_instance()); if (!Engine::get_singleton()->is_editor_hint()) set_process(_s_entity_data.is_valid()); if (gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_PLAYER || gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_DISPLAY) { setup_actionbars(); } if (gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_AI) { sets_entity_name(_s_entity_data->get_name()); } int chl = _s_level; int chxp = _s_xp; _s_level = 1; levelups(chl - 1); sets_xp(chxp); if (ESS::get_singleton()->get_allow_class_spell_learning()) { Ref class_profile = ProfileManager::get_singleton()->getc_player_profile()->get_class_profile(_s_entity_data->get_path()); if (class_profile.is_valid() && class_profile->has_custom_data("spells")) { Vector spells = class_profile->get_custom_data("spells"); for (int i = 0; i < spells.size(); ++i) { spell_adds_id(ESS::get_singleton()->get_resource_db()->spell_path_to_id(spells.get(i))); } } } if (ESS::get_singleton()->get_allow_class_recipe_learning()) { Ref class_profile = ProfileManager::get_singleton()->getc_player_profile()->get_class_profile(_s_entity_data->get_path()); if (class_profile.is_valid() && class_profile->has_custom_data("recipes")) { Vector recipes = class_profile->get_custom_data("recipes"); for (int i = 0; i < recipes.size(); ++i) { craft_adds_recipe_id(ESS::get_singleton()->get_resource_db()->craft_recipe_path_to_id(recipes.get(i))); } } } } void Entity::setup_actionbars() { if (!gets_entity_data().is_valid()) { return; } if (is_deserialized()) { return; } get_action_bar_profile(); /* ProfileManager *pm = ProfileManager::get_singleton(); if (pm != NULL) { Ref cp = get_class_profile(); if (cp.is_valid()) { set_actionbar_locked(cp->get_actionbar_locked()); _action_bar_profile = cp->get_default_action_bar_profile(); get_action_bar_profile()->clear_action_bars(); Ref abp = cp->get_action_bar_profile(); get_action_bar_profile()->from_actionbar_profile(abp); } }*/ if (!gets_bag().is_valid()) { Ref bag; bag.instance(); bag->set_size(gets_entity_data()->get_bag_size()); sets_bag(bag); } } // AI bool Entity::gets_is_pet() { return _s_pet_owner; } bool Entity::getc_is_pet() { return _c_pet_owner; } Entity *Entity::pet_gets_owner() { return _s_pet_owner; } void Entity::pet_sets_owner(Entity *entity) { _s_pet_owner = entity; } void Entity::pet_sets_owner_bind(Node *entity) { if (!entity) { return; } Entity *e = cast_to(entity); if (!e) { return; } return pet_sets_owner(e); } int Entity::pet_gets_formation_index() { return _s_pet_formation_index; } void Entity::pet_sets_formation_index(int value) { _s_pet_formation_index = value; } EntityEnums::AIStates Entity::pet_gets_ai_state() { return _s_pet_ai_state; } void Entity::pet_sets_ai_state(EntityEnums::AIStates value) { _s_pet_ai_state = value; } EntityEnums::EntityController Entity::gets_original_entity_controller() { return _s_entity_controller; } void Entity::sets_original_entity_controller(EntityEnums::EntityController value) { _s_entity_controller = value; } EntityEnums::EntityController Entity::gets_entity_controller() { return _s_entity_controller; } void Entity::sets_entity_controller(EntityEnums::EntityController value) { _s_entity_controller = value; ORPC(setc_entity_controller, value); } EntityEnums::EntityController Entity::getc_entity_controller() { return _s_entity_controller; } void Entity::setc_entity_controller(EntityEnums::EntityController value) { if (_c_entity_controller == value) { return; } _c_entity_controller = value; emit_signal("onc_entity_controller_changed"); } bool Entity::getc_is_controlled() { if (is_inside_tree() && get_tree()->has_network_peer()) { return (_c_entity_controller == EntityEnums::ENITIY_CONTROLLER_PLAYER) && (get_network_master() == get_tree()->get_network_unique_id()); } else { return _c_entity_controller == EntityEnums::ENITIY_CONTROLLER_PLAYER; } } Ref Entity::gets_ai() { return _s_ai; } void Entity::sets_ai(Ref value) { if (_s_ai.is_valid()) { _s_ai->set_owner(NULL); _s_ai.unref(); } _s_ai = value; _s_ai->set_owner(this); } //// Pets //// void Entity::pet_adds(Entity *entity) { ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); //the owner always want to see his pet, and you pet will always want to see the owner sees_add(entity); entity->sees_add(this); entity->pet_sets_owner(this); _s_pets.push_back(entity); entity->sets_ai_state_stored(entity->gets_ai_state()); entity->sets_ai_state(_s_pet_ai_state); entity->sets_entity_controller(EntityEnums::ENITIY_CONTROLLER_AI); entity->pet_sets_formation_index(_s_pets.size()); //full callback stack spet_added } void Entity::pet_adds_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); pet_adds(e); } Entity *Entity::pet_gets(int index) { ERR_FAIL_INDEX_V(index, _s_pets.size(), NULL); return _s_pets.get(index); } void Entity::pet_removes_index(int index) { ERR_FAIL_INDEX(index, _s_pets.size()); Entity *entity = _s_pets.get(index); _s_pets.remove(index); sees_remove(entity); for (int i = 0; i < _s_pets.size(); ++i) { Entity *pet = _s_pets.get(index); ERR_CONTINUE(!ObjectDB::instance_validate(pet)); _s_pets.get(i)->pet_sets_formation_index(i); } ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); entity->pet_sets_owner(NULL); entity->sets_ai_state(entity->gets_ai_state_stored()); entity->sets_entity_controller(entity->gets_original_entity_controller()); //full callback stack spet_added } void Entity::pet_removes(Entity *entity) { for (int i = 0; i < _s_pets.size(); ++i) { if (_s_pets.get(i) == entity) { pet_removes_index(i); return; } } } void Entity::pet_removes_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); pet_removes(e); } int Entity::pet_gets_count() { return _s_pets.size(); } void Entity::pet_addc_path(NodePath path) { Node *n = get_node_or_null(path); Entity *entity = Object::cast_to(n); ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); pet_addc(entity); } void Entity::pet_addc(Entity *entity) { ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); _c_pets.push_back(entity); //full callback stack spet_added } void Entity::pet_addc_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); pet_addc(e); } Entity *Entity::pet_getc(int index) { ERR_FAIL_INDEX_V(index, _c_pets.size(), NULL); return _c_pets.get(index); } void Entity::pet_removec_index(int index) { ERR_FAIL_INDEX(index, _c_pets.size()); //Entity *entity = _c_pets.get(index); _c_pets.remove(index); //ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); //full callback stack spet_added } void Entity::pet_removec(Entity *entity) { for (int i = 0; i < _c_pets.size(); ++i) { if (_c_pets.get(i) == entity) { pet_removec_index(i); return; } } } void Entity::pet_removec_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); pet_removec(e); } int Entity::pet_getc_count() { return _s_pets.size(); } //// Profiles //// Ref Entity::get_class_profile() { ERR_FAIL_COND_V(!ProfileManager::get_singleton(), Ref()); return ProfileManager::get_singleton()->getc_player_profile()->get_class_profile(_s_entity_data->get_path()); } //// Serialization //// bool Entity::is_deserialized() { return _deserialized; } Dictionary Entity::to_dict() { return call("_to_dict"); } void Entity::from_dict(const Dictionary &dict) { _deserialized = true; call("_from_dict", dict); emit_signal("deserialized", this); } Dictionary Entity::_to_dict() { Dictionary dict; //// Transforms //// //Not needed (at least atm) //// PlayerData //// dict["guid"] = _s_guid; //dict["entity_data_id"] = _s_class_id; if (_s_entity_data.is_valid()) dict["entity_data_path"] = _s_entity_data->get_path(); else dict["entity_data_path"] = _s_entity_data_path; //int _s_entity_player_type; dict["type"] = _s_type; dict["model_index"] = _s_model_index; dict["level"] = _s_level; dict["xp"] = gets_xp(); dict["money"] = _s_money; //dict["send_flag"] = _s_send_flag; dict["entity_name"] = _s_entity_name; dict["interaction_type"] = static_cast(_s_interaction_type); //int _s_is_dead; dict["seed"] = _s_seed; dict["entity_type"] = _s_entity_type; dict["immunity_flags"] = _s_immunity_flags; dict["entity_flags"] = _s_entity_flags; //dict["entity_controller"] = _s_entity_controller; //dict["entity_controller"] = _s_original_entity_controller; //// Stats //// Dictionary sd; for (int i = 0; i < _stats.size(); ++i) { Dictionary sdict; sdict["base"] = stat_get_base(i); sdict["base_calculated"] = stat_get_base_calculated(i); sdict["bonus"] = stat_get_bonus(i); sdict["percent"] = stat_get_percent(i); sdict["current"] = stat_gets_current(i); sd[i] = sdict; } dict["stats"] = sd; //// Equipment //// Dictionary equipment; for (int i = 0; i < _s_equipment.size(); ++i) { Ref ii = _s_equipment[i]; if (ii.is_valid()) equipment[i] = ii->to_dict(); } dict["equipment"] = equipment; //// Resources //// Dictionary rd; for (int i = 0; i < _s_resources.size(); ++i) { Ref r = _s_resources.get(i); ERR_CONTINUE(!r.is_valid()); rd[String::num(i)] = r->to_dict(); } dict["resources"] = rd; //// GCD //// dict["gcd"] = _s_gcd; //// States //// Dictionary stated; for (int i = 0; i < EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX; ++i) { stated[i] = _s_states[i]; } dict["states"] = stated; dict["state"] = _s_state; //// SpellCastData //// //Not needed //Ref _s_spell_cast_info; //Ref _c_spell_cast_info; //// AuraComponent //// Dictionary auras; for (int i = 0; i < _s_auras.size(); ++i) { auras[i] = _s_auras.get(i)->to_dict(); } dict["auras"] = auras; //// Cooldowns //// Dictionary cds; for (int i = 0; i < _s_cooldowns.size(); ++i) { Dictionary cdict; cdict["path"] = ESS::get_singleton()->get_resource_db()->spell_id_to_path(_s_cooldowns[i].id); cdict["remaining"] = _s_cooldowns[i].cooldown; cds[i] = cdict; } dict["cooldowns"] = cds; Dictionary ccds; for (int i = 0; i < _s_category_cooldowns.size(); ++i) { Dictionary ccdict; ccdict["path"] = ESS::get_singleton()->get_resource_db()->spell_id_to_path(_s_category_cooldowns[i].id); ccdict["remaining"] = _s_category_cooldowns[i].cooldown; ccds[i] = ccdict; } dict["category_cooldowns"] = ccds; dict["active_category_cooldowns"] = _s_active_category_cooldowns; //// Talents //// dict["free_class_talent_points"] = _s_free_class_talent_points; dict["class_talents"] = _s_class_talents; dict["free_character_talent_points"] = _s_free_character_talent_points; dict["character_talents"] = _s_character_talents; //// Data //// Array entity_datas; for (int i = 0; i < _s_data.size(); ++i) { entity_datas.append(_s_data.get(i)->to_dict()); } dict["entity_datas"] = entity_datas; //// Crafting //// Dictionary known_recipes; for (int i = 0; i < _s_craft_recipes.size(); ++i) { known_recipes[i] = _s_craft_recipes.get(i)->get_path(); } dict["known_recipes"] = known_recipes; //// Known Spells //// if (ESS::get_singleton() && ESS::get_singleton()->get_use_spell_points()) { dict["free_spell_points"] = _s_free_spell_points; } Dictionary known_spells; for (int i = 0; i < _s_spells.size(); ++i) { known_spells[i] = _s_spells.get(i)->get_path(); } dict["known_spells"] = known_spells; //// Skills //// Dictionary skills; for (int i = 0; i < _s_skills.size(); ++i) { skills[i] = _s_skills.get(i)->to_dict(); } dict["skills"] = skills; //// Bags //// if (_s_bag.is_valid()) dict["bag"] = _s_bag->to_dict(); //// Actionbars //// dict["actionbar_locked"] = _actionbar_locked; if (_action_bar_profile.is_valid()) dict["actionbar_profile"] = _action_bar_profile->to_dict(); // AI //not needed //Pets //Not yet properly implemented // Callbacks //Probably not needed //Vector > _physics_process_scis; return dict; } void Entity::_from_dict(const Dictionary &dict) { //// Transforms //// //Not needed for now //// PlayerData //// sets_guid(dict.get("guid", 0)); sets_entity_type(dict.get("type", 0)); //entity_data_path at end sets_model_index(static_cast(static_cast(dict.get("model_index", 0)))); /* if (ESS::get_singleton()->get_use_global_class_level()) { _s_level = (dict.get("class_level", 0)); _s_xp = (dict.get("class_xp", 0)); } else { sets_class_level(dict.get("class_level", 0)); sets_xp(dict.get("xp", 0)); } */ sets_level(dict.get("level", 0)); sets_xp(dict.get("xp", 0)); sets_money(dict.get("money", 0)); sets_entity_name(dict.get("entity_name", "")); sets_entity_interaction_type(static_cast(static_cast(dict.get("interaction_type", 0)))); //int _s_is_dead; sets_seed(dict.get("seed", _s_seed)); //EntityPlayerType not needed sets_immunity_flags(dict.get("immunity_flags", 0)); sets_entity_flags(dict.get("entity_flags", 0)); //EntityEnums::EntityController contr = static_cast(static_cast(dict.get("entity_controller", 0))); //sets_original_entity_controller(contr); //sets_entity_controller(contr); //// Stats //// Dictionary stats = dict.get("stats", Dictionary()); for (int i = 0; i < _stats.size(); ++i) { Dictionary sd = stats.get(String::num(i), Dictionary()); stat_set_base(i, sd.get("base", 0)); stat_set_base_calculated(i, sd.get("base_calculated", 0)); stat_set_bonus(i, sd.get("bonus", 0)); stat_set_percent(i, sd.get("percent", 1)); float curr = sd.get("current", 0); stat_sets_current(i, curr); stat_setc_current(i, curr); stat_set_dirty(i, true); } //// Equipment //// Dictionary equipment = dict.get("equipment", Dictionary()); for (int i = 0; i < _s_equipment.size(); ++i) { if (equipment.has(String::num(i))) { Ref ii = _s_equipment[i]; if (!ii.is_valid()) { ii.instance(); } ii->from_dict(equipment[String::num(i)]); _s_equipment.write[i] = ii; _c_equipment.write[i] = ii; } } //// Resources //// _s_resources.resize(EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN); _c_resources.resize(EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN); Dictionary rd = dict.get("resources", Dictionary()); Dictionary hpdict = rd.get(String::num(EntityEnums::ENTITY_RESOURCE_INDEX_HEALTH), Dictionary()); _s_resources.get(EntityEnums::ENTITY_RESOURCE_INDEX_HEALTH)->from_dict(hpdict); _c_resources.get(EntityEnums::ENTITY_RESOURCE_INDEX_HEALTH)->from_dict(hpdict); Dictionary speeddict = rd.get(String::num(EntityEnums::ENTITY_RESOURCE_INDEX_SPEED), Dictionary()); _s_resources.get(EntityEnums::ENTITY_RESOURCE_INDEX_SPEED)->from_dict(speeddict); _c_resources.get(EntityEnums::ENTITY_RESOURCE_INDEX_SPEED)->from_dict(speeddict); for (int i = EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN; i < rd.size(); ++i) { Dictionary ird = rd.get(String::num(i), Dictionary()); StringName data_path = ird.get("data_path", ""); Ref resd = ESS::get_singleton()->get_resource_db()->get_entity_resource_path(data_path); ERR_CONTINUE(!resd.is_valid()); Ref res = resd->duplicate(); ERR_CONTINUE(!res.is_valid()); res->from_dict(ird); resource_adds(res); } //// GCD //// _s_gcd = dict.get("gcd", 0); _c_gcd = _s_gcd; //// States //// Dictionary statesd = dict.get("states", Dictionary()); for (int i = 0; i < EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX; ++i) { _s_states[i] = statesd.get(String::num(i), 0); } _s_state = dict.get("state", Dictionary()); _c_state = _s_state; //// SpellCastData //// //Not needed //// Auras //// _s_auras.clear(); _c_auras.clear(); Dictionary auras = dict.get("auras", Dictionary()); for (int i = 0; i < auras.size(); ++i) { Ref r; r.instance(); r->from_dict(auras.get(String::num(i), Dictionary())); r->set_owner(this); r->resolve_references(this); _s_auras.push_back(r); //_c_auras.push_back(r); } //// Cooldowns //// _s_cooldowns.clear(); _c_cooldowns.clear(); Dictionary cds = dict.get("cooldowns", Dictionary()); for (int i = 0; i < cds.size(); ++i) { Dictionary cddict = cds.get(String::num(i), Dictionary()); Cooldown cd; cd.path = dict.get("path", ""); cd.id = ESS::get_singleton()->get_resource_db()->spell_path_to_id(cd.path); cd.cooldown = dict.get("remaining", 0); _s_cooldowns.push_back(cd); _c_cooldowns.push_back(cd); } Dictionary ccds = dict.get("category_cooldowns", Dictionary()); for (int i = 0; i < ccds.size(); ++i) { Dictionary ccdict = ccds.get(String::num(i), Dictionary()); Cooldown ccd; ccd.path = dict.get("path", ""); ccd.id = ESS::get_singleton()->get_resource_db()->spell_path_to_id(ccd.path); ccd.cooldown = dict.get("remaining", 0); _s_category_cooldowns.push_back(ccd); _c_category_cooldowns.push_back(ccd); } _s_active_category_cooldowns = dict.get("active_category_cooldowns", 0); _c_active_category_cooldowns = _s_active_category_cooldowns; //// Class Talents //// _s_free_class_talent_points = dict.get("free_class_talent_points", 0); _c_free_class_talent_points = _s_free_class_talent_points; Vector class_talents = dict.get("class_talents", Vector()); for (int i = 0; i < class_talents.size(); ++i) { class_talent_adds(class_talents[i]); } //// Character Talents //// _s_free_character_talent_points = dict.get("free_character_talent_points", 0); _c_free_character_talent_points = _s_free_character_talent_points; Vector character_talents = dict.get("character_talents", Vector()); for (int i = 0; i < character_talents.size(); ++i) { character_talent_adds(character_talents[i]); } //// Data //// Array entity_datas = dict.get("entity_datas", Array()); for (int i = 0; i < entity_datas.size(); ++i) { Dictionary entry = entity_datas.get(i); String class_name = dict.get("class_name", EntityDataContainer::get_class_static()); if (ClassDB::can_instance(class_name) && ClassDB::is_parent_class(class_name, EntityDataContainer::get_class_static())) { Ref data = Ref(ClassDB::instance(class_name)); if (data.is_valid()) { data->from_dict(entry); _s_data.push_back(data); _c_data.push_back(data); } } } //// Crafting //// _s_craft_recipes.clear(); _c_craft_recipes.clear(); Dictionary known_recipes = dict.get("known_recipes", Dictionary()); for (int i = 0; i < known_recipes.size(); ++i) { StringName crn = known_recipes.get(String::num(i), ""); if (ESS::get_singleton() != NULL) { Ref cr = ESS::get_singleton()->get_resource_db()->get_craft_recipe_path(crn); if (cr.is_valid()) { craft_adds_recipe(cr); } } } //// Known Spells //// if (ESS::get_singleton() && ESS::get_singleton()->get_use_spell_points()) { sets_free_spell_points(dict.get("free_spell_points", 0)); } Dictionary known_spells = dict.get("known_spells", Dictionary()); for (int i = 0; i < known_spells.size(); ++i) { StringName spell_path = known_spells.get(String::num(i), ""); if (ESS::get_singleton() != NULL) { Ref sp = ESS::get_singleton()->get_resource_db()->get_spell_path(spell_path); if (sp.is_valid()) { _s_spells.push_back(sp); _c_spells.push_back(sp); } } } //// Skills //// Dictionary skills = dict.get("skills", Dictionary()); for (int i = 0; i < skills.size(); ++i) { Ref r; r.instance(); r->from_dict(skills.get(String::num(i), Dictionary())); _s_skills.push_back(r); _c_skills.push_back(r); } //// Bags //// Dictionary bagd = dict.get("bag", Dictionary()); if (!bagd.empty()) { if (!_s_bag.is_valid()) { Ref bag; bag.instance(); bag->from_dict(bagd); sets_bag(bag); } else { _s_bag->from_dict(bagd); } } //// Actionbars //// _actionbar_locked = dict.get("actionbar_locked", false); if (dict.has("actionbar_profile")) { if (!_action_bar_profile.is_valid()) _action_bar_profile.instance(); _action_bar_profile->from_dict(dict.get("actionbar_profile", Dictionary())); } StringName edp = dict.get("entity_data_path", ""); if (ESS::get_singleton() != NULL) { sets_entity_data(ESS::get_singleton()->get_resource_db()->get_entity_data_path(edp)); } sets_entity_data_path(edp); // AI //Not needed right now //Pets //NYI // Networking //Not Needed // Callbacks //Not Needed } ////// Stat System ////// bool Entity::gets_is_dead() { return _s_is_dead; } bool Entity::getc_is_dead() { return _c_is_dead; } bool Entity::gcd_hasc() const { return _c_gcd >= 0.000000001; } bool Entity::gcd_hass() const { return _s_gcd >= 0.000000001; } float Entity::gcd_getc() const { return _c_gcd; } void Entity::gcd_setc(const float value) { _c_gcd = value; } float Entity::gcd_gets() const { return _s_gcd; } void Entity::gcd_sets(const float value) { _s_gcd = value; } void Entity::gcd_starts(float value) { _s_gcd = value; notification_sgcd_started(); ORPC(gcd_startc, value); } void Entity::gcd_startc(float value) { _c_gcd = value; notification_cgcd_started(); } //// States //// int Entity::gets_state() { return _s_state; } void Entity::sets_state(int state) { _s_state = state; emit_signal("sstate_changed", state); VRPC(setc_state, state); } int Entity::getc_state() { return _c_state; } void Entity::setc_state(int state) { _c_state = state; emit_signal("cstate_changed", state); } void Entity::adds_state_ref(int state_index) { ERR_FAIL_INDEX(state_index, EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); if (_s_states[state_index]++ == 0) { sets_state(gets_state() | EntityEnums::get_state_flag_for_index(state_index)); } } void Entity::removes_state_ref(int state_index) { ERR_FAIL_INDEX(state_index, EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); if (--_s_states[state_index] == 0) { sets_state(gets_state() ^ EntityEnums::get_state_flag_for_index(state_index)); } } PoolIntArray Entity::states_gets() const { PoolIntArray arr; arr.resize(EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); PoolIntArray::Write w = arr.write(); for (int i = 0; i < EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX; ++i) { w[i] = _s_states[i]; } return arr; } void Entity::states_sets(const PoolIntArray &data) { ERR_FAIL_COND(data.size() <= EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); for (int i = 0; i < EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX; ++i) { _s_states[i] = data[i]; } } //// Crafting System //// void Entity::craft_crequest(int id) { crafts(id); } void Entity::crafts(int id) { if (has_method("_crafts")) { call("_crafts", id); } } bool Entity::craft_hass_recipe(Ref craft_recipe) { for (int i = 0; i < _s_craft_recipes.size(); ++i) { if (_s_craft_recipes.get(i) == craft_recipe) { return true; } } return false; } bool Entity::craft_hass_recipe_id(int id) { for (int i = 0; i < _s_craft_recipes.size(); ++i) { Ref cr = _s_craft_recipes.get(i); ERR_CONTINUE(!cr.is_valid()); if (cr->get_id() == id) { return true; } } return false; } void Entity::craft_adds_recipe(Ref craft_recipe) { ERR_FAIL_COND(!craft_recipe.is_valid()); if (craft_hass_recipe(craft_recipe)) { return; } _s_craft_recipes.push_back(craft_recipe); emit_signal("crafts_recipe_added", this, craft_recipe); ORPC(craft_addc_recipe_id, craft_recipe->get_id()); } void Entity::craft_adds_recipe_id(int id) { ERR_FAIL_COND(!ESS::get_singleton()); if (craft_hass_recipe_id(id)) { return; } Ref craft_recipe = ESS::get_singleton()->get_resource_db()->get_craft_recipe(id); ERR_FAIL_COND(!craft_recipe.is_valid()); _s_craft_recipes.push_back(craft_recipe); if (ESS::get_singleton()->get_allow_class_recipe_learning() && (_s_entity_player_type == EntityEnums::ENTITY_PLAYER_TYPE_PLAYER || gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_DISPLAY)) { Ref class_profile = ProfileManager::get_singleton()->getc_player_profile()->get_class_profile(_s_entity_data->get_path()); if (class_profile->has_custom_data("recipes")) { Vector recipes = class_profile->get_custom_data("recipes"); bool found = false; for (int i = 0; i < recipes.size(); ++i) { if (recipes[i] == craft_recipe->get_path()) { found = true; break; } } if (!found) { recipes.push_back(craft_recipe->get_path()); class_profile->set_custom_data("recipes", recipes); } } else { Vector recipes; recipes.push_back(craft_recipe->get_path()); class_profile->set_custom_data("recipes", recipes); } } emit_signal("crafts_recipe_added", this, craft_recipe); ORPC(craft_addc_recipe_id, id); } void Entity::craft_removes_recipe(Ref craft_recipe) { for (int i = 0; i < _s_craft_recipes.size(); ++i) { if (_s_craft_recipes.get(i) == craft_recipe) { _s_craft_recipes.remove(i); break; } } emit_signal("crafts_recipe_removed", this, craft_recipe); ORPC(craft_removec_recipe, craft_recipe); } void Entity::craft_removes_recipe_id(int id) { Ref craft_recipe; for (int i = 0; i < _s_craft_recipes.size(); ++i) { craft_recipe = _s_craft_recipes.get(i); if (craft_recipe->get_id() == id) { _s_craft_recipes.remove(i); break; } } emit_signal("crafts_recipe_removed", this, craft_recipe); ORPC(craft_removec_recipe_id, id); } Ref Entity::craft_gets_recipe(int index) { ERR_FAIL_INDEX_V(index, _s_craft_recipes.size(), Ref()); return _s_craft_recipes.get(index); } Ref Entity::craft_gets_recipe_id(int id) { for (int i = 0; i < _s_craft_recipes.size(); ++i) { Ref craft_recipe = _s_craft_recipes.get(i); if (craft_recipe->get_id() == id) { return craft_recipe; } } return Ref(); } int Entity::craft_gets_recipe_count() { return _s_craft_recipes.size(); } bool Entity::craft_hasc_recipe(Ref craft_recipe) { for (int i = 0; i < _c_craft_recipes.size(); ++i) { if (_c_craft_recipes.get(i) == craft_recipe) { return true; } } return false; } bool Entity::craft_hasc_recipe_id(int id) { for (int i = 0; i < _c_craft_recipes.size(); ++i) { Ref cr = _c_craft_recipes.get(i); ERR_CONTINUE(!cr.is_valid()); if (cr->get_id() == id) { return true; } } return false; } void Entity::craft_addc_recipe(Ref craft_recipe) { if (craft_hasc_recipe(craft_recipe)) { return; } _c_craft_recipes.push_back(craft_recipe); emit_signal("ccraft_recipe_added", this, craft_recipe); } void Entity::craft_addc_recipe_id(int id) { ERR_FAIL_COND(!ESS::get_singleton()); if (craft_hasc_recipe_id(id)) { return; } Ref craft_recipe = ESS::get_singleton()->get_resource_db()->get_craft_recipe(id); ERR_FAIL_COND(!craft_recipe.is_valid()); _c_craft_recipes.push_back(craft_recipe); emit_signal("ccraft_recipe_added", this, craft_recipe); } void Entity::craft_removec_recipe(Ref craft_recipe) { for (int i = 0; i < _c_craft_recipes.size(); ++i) { if (_c_craft_recipes.get(i) == craft_recipe) { _c_craft_recipes.remove(i); break; } } emit_signal("ccraft_recipe_removed", this, craft_recipe); } void Entity::craft_removec_recipe_id(int id) { Ref craft_recipe; for (int i = 0; i < _c_craft_recipes.size(); ++i) { craft_recipe = _c_craft_recipes.get(i); if (craft_recipe->get_id() == id) { _c_craft_recipes.remove(i); break; } } emit_signal("ccraft_recipe_removed", this, craft_recipe); } Ref Entity::craft_getc_recipe(int index) { ERR_FAIL_INDEX_V(index, _c_craft_recipes.size(), Ref()); return _c_craft_recipes.get(index); } int Entity::craft_getc_recipe_count() { return _c_craft_recipes.size(); } Vector Entity::scraft_recipes_get() { VARIANT_ARRAY_GET(_s_craft_recipes); } void Entity::scraft_recipes_set(const Vector &resources) { VARIANT_ARRAY_SET(resources, _s_craft_recipes, CraftRecipe); } //// Stat System //// EntityStat Entity::get_stat(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), EntityStat()); return _stats[stat_id]; } void Entity::set_stat(const int stat_id, const EntityStat &entry) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.set(stat_id, entry); } bool Entity::stat_get_dirty(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), false); return _stats[stat_id].dirty; } void Entity::stat_set_dirty(const int stat_id, const bool value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].dirty = value; } float Entity::stat_get_base(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].base; } void Entity::stat_set_base(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].base = value; stat_recalculate(stat_id); } void Entity::stat_mod_base(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].base += value; stat_recalculate(stat_id); } float Entity::stat_get_base_calculated(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].base_calculated; } void Entity::stat_set_base_calculated(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].base_calculated = value; stat_recalculate(stat_id); } float Entity::stat_get_bonus(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].bonus; } void Entity::stat_set_bonus(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].bonus = value; stat_recalculate(stat_id); } void Entity::stat_mod_bonus(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].bonus += value; stat_recalculate(stat_id); } float Entity::stat_get_percent(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].percent; } void Entity::stat_set_percent(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].percent = value; stat_recalculate(stat_id); } void Entity::stat_mod_percent(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].percent += value; stat_recalculate(stat_id); } void Entity::stat_mod(const int stat_id, const float base, const float bonus, const float percent) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].base += base; _stats.write[stat_id].bonus += bonus; _stats.write[stat_id].percent += percent; stat_recalculate(stat_id); } float Entity::stat_gets_current(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].scurrent; } void Entity::stat_sets_current(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].scurrent = value; } float Entity::stat_getc_current(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), 0); return _stats[stat_id].ccurrent; } void Entity::stat_setc_current(const int stat_id, const float value) { ERR_FAIL_INDEX(stat_id, _stats.size()); _stats.write[stat_id].ccurrent = value; notification_cstat_changed(stat_id, value); } void Entity::stat_recalculate(const int stat_id) { ERR_FAIL_INDEX(stat_id, _stats.size()); stat_sets_current(stat_id, (stat_get_base(stat_id) + stat_get_base_calculated(stat_id) + stat_get_bonus(stat_id)) * (stat_get_percent(stat_id) / 100.0)); stat_set_dirty(stat_id, true); notification_sstat_changed(stat_id, stat_gets_current(stat_id)); } void Entity::dies() { //serverside notification_sdeath(); //send an event to client VRPC(diec); //signal emit_signal("diesd", this); } void Entity::diec() { notification_cdeath(); } void Entity::notification_sstat_changed(const int statid, const float current) { for (int i = 0; i < _s_resources.size(); ++i) { _s_resources.get(i)->notification_sstat_changed(statid, current); } } void Entity::notification_cstat_changed(const int statid, const float current) { for (int i = 0; i < _c_resources.size(); ++i) { _c_resources.get(i)->notification_cstat_changed(statid, current); } } void Entity::ssend_stat(int id, int ccurrent) { ERR_FAIL_INDEX(id, _stats.size()); //Only the owner needs access to stats ORPC(creceive_stat, id, ccurrent); } void Entity::creceive_stat(int id, int ccurrent) { ERR_FAIL_INDEX(id, _stats.size()); stat_setc_current(id, ccurrent); } //// Equip Slots //// bool Entity::equip_should_deny(int equip_slot, Ref item) { if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) { if (_s_ai->equip_should_deny(this, equip_slot, item)) { return true; } } for (int i = 0; i < _s_auras.size(); ++i) { Ref ad = _s_auras.get(i); if (ad->get_aura()->equip_should_deny(ad, equip_slot, item)) { return true; } } if (has_method("_equip_should_deny")) { if (call("_equip_should_deny", equip_slot, item)) { return true; } } return false; } void Entity::equip_son_success(int equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) { _s_ai->equip_son_success(this, equip_slot, item, old_item, bag_slot); } for (int i = 0; i < _s_auras.size(); ++i) { Ref ad = _s_auras.get(i); ad->get_aura()->equip_son_success(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_equip_son_success")) { call("_equip_son_success", equip_slot, item, old_item, bag_slot); } emit_signal("equip_son_success", this, equip_slot, item, old_item, bag_slot); } void Entity::equip_son_fail(int equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) { _s_ai->equip_son_fail(this, equip_slot, item, old_item, bag_slot); } for (int i = 0; i < _s_auras.size(); ++i) { Ref ad = _s_auras.get(i); ad->get_aura()->equip_son_fail(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_equip_son_fail")) { call("_equip_son_fail", equip_slot, item, old_item, bag_slot); } emit_signal("equip_son_fail", this, equip_slot, item, old_item, bag_slot); } void Entity::equip_con_success(int equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) { _s_ai->equip_con_success(this, equip_slot, item, old_item, bag_slot); } for (int i = 0; i < _c_auras.size(); ++i) { Ref ad = _c_auras.get(i); ad->get_aura()->equip_con_success(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_equip_con_success")) { call("_equip_con_success", equip_slot, item, old_item, bag_slot); } emit_signal("equip_con_success", this, equip_slot, item, old_item, bag_slot); } void Entity::equip_con_fail(int equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_controller == EntityEnums::ENITIY_CONTROLLER_AI && _s_ai.is_valid()) { _s_ai->equip_con_fail(this, equip_slot, item, old_item, bag_slot); } for (int i = 0; i < _c_auras.size(); ++i) { Ref ad = _c_auras.get(i); ad->get_aura()->equip_con_fail(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_equip_con_fail")) { call("_equip_con_fail", equip_slot, item, old_item, bag_slot); } emit_signal("equip_con_fail", this, equip_slot, item, old_item, bag_slot); } void Entity::equip_crequest(int equip_slot, int bag_slot) { RPCS(equips, equip_slot, bag_slot) } void Entity::equips(int equip_slot, int bag_slot) { call("_equips", equip_slot, bag_slot); } void Entity::_equips(int equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, _s_equipment.size()); ERR_FAIL_COND(!_s_bag.is_valid()); Ref bag_item = _s_bag->get_item(bag_slot); Ref equipped_item = equip_gets_slot(equip_slot); if (!equip_can_equip_item(equip_slot, bag_item)) { ORPC(equip_cfail, equip_slot, bag_slot); return; } if (equip_should_deny(equip_slot, bag_item)) { ORPC(equip_cfail, equip_slot, bag_slot); return; } //check armor type //check required skills if (equipped_item.is_valid()) equip_deapplys_item(equipped_item); if (bag_item.is_valid()) equip_applys_item(bag_item); equip_sets_slot(equip_slot, bag_item); _s_bag->add_item_at(bag_slot, equipped_item, false); ORPC(equip_csuccess, equip_slot, bag_slot); } void Entity::equip_csuccess(int equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, _c_equipment.size()); ERR_FAIL_COND(!_c_bag.is_valid()); Ref old_bag_item = _c_bag->get_item(bag_slot); Ref old_equipped_item = equip_getc_slot(equip_slot); _c_bag->add_item_at(bag_slot, old_equipped_item); equip_setc_slot(equip_slot, old_bag_item); if (old_equipped_item.is_valid()) equip_deapplyc_item(old_equipped_item); if (old_bag_item.is_valid()) equip_applyc_item(old_bag_item); equip_con_success(equip_slot, old_bag_item, old_equipped_item, bag_slot); } void Entity::equip_cfail(int equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, _c_equipment.size()); ERR_FAIL_COND(!_c_bag.is_valid()); Ref bag_item = _c_bag->get_item(bag_slot); Ref equipped_item = equip_getc_slot(equip_slot); equip_con_fail(equip_slot, equipped_item, bag_item, bag_slot); } Ref Entity::equip_gets_slot(int index) { ERR_FAIL_INDEX_V(index, _s_equipment.size(), Ref()); return _s_equipment[index]; } void Entity::equip_sets_slot(int index, Ref item) { ERR_FAIL_INDEX(index, _s_equipment.size()); _s_equipment.write[index] = item; } Ref Entity::equip_getc_slot(int index) { ERR_FAIL_INDEX_V(index, _c_equipment.size(), Ref()); return _c_equipment[index]; } void Entity::equip_setc_slot(int index, Ref item) { ERR_FAIL_INDEX(index, _c_equipment.size()); _c_equipment.write[index] = item; } bool Entity::equip_can_equip_item(int equip_slot, Ref item) { return call("_equip_can_equip_item", equip_slot, item); } bool Entity::_equip_can_equip_item(int equip_slot, Ref item) { //deequip if (!item.is_valid()) { return true; } Ref it = item->get_item_template(); ERR_FAIL_COND_V(!it.is_valid(), false); return it->get_equip_slot() == equip_slot; } void Entity::equip_applys_item(Ref item) { call("_equip_applys_item", item); } void Entity::equip_deapplys_item(Ref item) { call("_equip_deapplys_item", item); } void Entity::_equip_applys_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); for (int i = 0; i < item->stat_modifier_get_count(); ++i) { int sid = item->stat_modifier_get_stat_id(i); stat_mod_base(sid, item->stat_modifier_get_base_mod(i)); stat_mod_bonus(sid, item->stat_modifier_get_bonus_mod(i)); stat_mod_percent(sid, item->stat_modifier_get_percent_mod(i)); } } void Entity::_equip_deapplys_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); for (int i = 0; i < item->stat_modifier_get_count(); ++i) { int sid = item->stat_modifier_get_stat_id(i); stat_mod_base(sid, -item->stat_modifier_get_base_mod(i)); stat_mod_bonus(sid, -item->stat_modifier_get_bonus_mod(i)); stat_mod_percent(sid, -item->stat_modifier_get_percent_mod(i)); } } void Entity::equip_applyc_item(Ref item) { call("_equip_applyc_item", item); } void Entity::equip_deapplyc_item(Ref item) { call("_equip_deapplyc_item", item); } void Entity::_equip_applyc_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); if (it->get_model_visual().is_valid() && ObjectDB::instance_validate(_character_skeleton)) { if (_character_skeleton->has_method("add_model_visual")) _character_skeleton->call("add_model_visual", it->get_model_visual()); } } void Entity::_equip_deapplyc_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); if (it->get_model_visual().is_valid() && ObjectDB::instance_validate(_character_skeleton)) { if (_character_skeleton->has_method("remove_model_visual")) _character_skeleton->call("remove_model_visual", it->get_model_visual()); } } //// Resources //// Ref Entity::resource_gets_index(int index) { ERR_FAIL_INDEX_V(index, _s_resources.size(), Ref()); return _s_resources.get(index); } Ref Entity::resource_gets_id(int id) { for (int i = EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN; i < _s_resources.size(); ++i) { Ref r = _s_resources.get(i); if (r->get_id() == id) { return r; } } return Ref(); } void Entity::resource_adds(Ref resource) { ERR_FAIL_COND(!resource.is_valid()); _s_resources.push_back(resource); resource->ons_added(this); notification_sentity_resource_added(resource); VRPCOBJP(resource_addc_rpc, _s_resources.size() - 1, JSON::print(resource->to_dict()), resource_addc, _s_resources.size() - 1, resource); } int Entity::resource_gets_count() { return _s_resources.size(); } void Entity::resource_removes(int index) { ERR_FAIL_INDEX(index, _s_resources.size()); Ref res = _s_resources.get(index); _s_resources.remove(index); notification_sentity_resource_removed(res); VRPC(resource_removec, index); } void Entity::resource_clears() { _s_resources.resize(EntityEnums::ENTITY_RESOURCE_INDEX_RESOURCES_BEGIN); VRPC(resource_clearc); } void Entity::resource_addc_rpc(int index, String data) { ERR_FAIL_COND(!ESS::get_singleton()); //Ref res; Dictionary dict = data_as_dict(data); /* String clsname = dict.get("id", "EntityResource"); res = Ref(Object::cast_to(ClassDB::instance(clsname))); ERR_FAIL_COND(!res.is_valid()); //res.instance(); String script_path = dict.get("script", ""); Ref