/* Copyright (c) 2019-2020 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 "../singletons/entity_data_manager.h" #include "../singletons/profile_manager.h" #include "../data/auras/aura.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/talent_row_data.h" #include "./skills/entity_skill.h" #include "core/script_language.h" #include "core/version.h" NodePath Entity::get_body_path() { return _body_path; } void Entity::set_body_path(NodePath value) { _body_path = value; _body = get_node_or_null(_body_path); #if VERSION_MAJOR < 4 if (ObjectDB::instance_validate(_body)) _body->set_owner(this); #else if (_body == NULL) _body->set_owner(this); #endif } Node *Entity::get_body() { return _body; } NodePath Entity::get_character_skeleton_path() { return _character_skeleton_path; } void Entity::set_character_skeleton_path(NodePath value) { _character_skeleton_path = value; _character_skeleton = get_node_or_null(_character_skeleton_path); } Node *Entity::get_character_skeleton() { return _character_skeleton; } //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)); } //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 EntityEnums::EntityType Entity::gets_entity_type() { return _s_entity_type; } void Entity::sets_entity_type(EntityEnums::EntityType value) { _s_entity_type = value; VRPC(setc_entity_type, value); } EntityEnums::EntityType Entity::getc_entity_type() { return _c_entity_type; } void Entity::setc_entity_type(EntityEnums::EntityType value) { _c_entity_type = value; } //Relations EntityEnums::EntityRelationType Entity::gets_relation_to_bind(Node *to) { Entity *e = Object::cast_to(to); #if VERSION_MAJOR < 4 ERR_FAIL_COND_V(!ObjectDB::instance_validate(e), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #else ERR_FAIL_COND_V(e == NULL, EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #endif return gets_relation_to(e); } EntityEnums::EntityRelationType Entity::gets_relation_to(Entity *to) { #if VERSION_MAJOR < 4 ERR_FAIL_COND_V(!ObjectDB::instance_validate(to), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #else ERR_FAIL_COND_V(to == NULL, EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #endif 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); #if VERSION_MAJOR < 4 ERR_FAIL_COND_V(!ObjectDB::instance_validate(e), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #else ERR_FAIL_COND_V(e == NULL, EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #endif return getc_relation_to(e); } EntityEnums::EntityRelationType Entity::getc_relation_to(Entity *to) { #if VERSION_MAJOR < 4 ERR_FAIL_COND_V(!ObjectDB::instance_validate(to), EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #else ERR_FAIL_COND_V(to == NULL, EntityEnums::ENTITY_RELATION_TYPE_NEUTRAL); #endif 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); } EntityEnums::EntityGender Entity::gets_gender() { return _s_gender; } void Entity::sets_gender(EntityEnums::EntityGender value) { _s_gender = value; VRPC(setc_gender, value); } EntityEnums::EntityGender Entity::getc_gender() { return _c_gender; } void Entity::setc_gender(EntityEnums::EntityGender value) { _c_gender = value; #if VERSION_MAJOR < 4 if (ObjectDB::instance_validate(_character_skeleton)) { #else if (_character_skeleton != NULL) { #endif if (_character_skeleton->has_method("set_gender")) _character_skeleton->call("set_gender", _c_gender); } } int Entity::gets_class_level() { return _s_class_level; } void Entity::sets_class_level(int value) { _s_class_level = value; emit_signal("son_character_level_changed", this, value); VRPC(setc_class_level, value); } int Entity::getc_class_level() { return _c_class_level; } void Entity::setc_class_level(int value) { _c_class_level = value; emit_signal("con_character_level_changed", this, value); } int Entity::gets_character_level() { return _s_character_level; } void Entity::sets_character_level(int value) { _s_character_level = value; emit_signal("son_character_level_changed", this, value); VRPC(setc_character_level, value); } int Entity::getc_character_level() { return _c_character_level; } void Entity::setc_character_level(int value) { _c_character_level = value; emit_signal("con_character_level_changed", this, value); } int Entity::gets_class_xp() { return _s_class_xp; } void Entity::sets_class_xp(int value) { _s_class_xp = value; ORPC(setc_class_xp, value); } int Entity::getc_class_xp() { return _c_class_xp; } void Entity::setc_class_xp(int value) { _c_class_xp = value; } int Entity::gets_character_xp() { return _s_character_xp; } void Entity::sets_character_xp(int value) { _s_character_xp = value; ORPC(setc_character_xp, value); } int Entity::getc_character_xp() { return _c_character_xp; } void Entity::setc_character_xp(int value) { _c_character_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 (EntityDataManager::get_instance() != NULL) { setc_entity_data(EntityDataManager::get_instance()->get_entity_data(_c_class_id)); } } Ref Entity::gets_entity_data() { return _s_entity_data; } void Entity::sets_entity_data(Ref value) { _s_class_id = 0; if (value.is_valid()) { _s_class_id = value->get_id(); } _s_entity_data = value; //setup(); 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; 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::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 && get_tree()->is_network_server()) set_network_master(info->get_network_owner()); sets_original_entity_controller(info->get_entity_controller()); sets_entity_controller(info->get_entity_controller()); sets_entity_name(info->get_entity_name()); sets_entity_data(info->get_entity_data()); if (!info->get_serialized_data().empty()) { from_dict(info->get_serialized_data()); } if (has_method("_setup")) { call_multilevel("_setup", info); } } void Entity::_setup(Ref info) { 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 = cc->get_stat_data(); ERR_FAIL_COND(!stat_data.is_valid()); for (int i = 0; i < Stat::STAT_ID_TOTAL_STATS; ++i) { Ref sde = stat_data->get_stat_data_int(i); _stats[i]->set_stat_data_entry(sde); } 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()->get_hide()) VRPCOBJ(addc_aura_rpc, JSON::print(ad->to_dict()), addc_aura, ad); } for (int i = 0; i < _s_resources.size(); ++i) { Ref res = _s_resources.get(i); ERR_CONTINUE(!res.is_valid()); res->resolve_references(); } for (int i = 0; i < _c_resources.size(); ++i) { Ref res = _c_resources.get(i); ERR_CONTINUE(!res.is_valid()); res->resolve_references(); } if (gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_PLAYER || gets_entity_player_type() == EntityEnums::ENTITY_PLAYER_TYPE_DISPLAY) { if (EntityDataManager::get_instance()->get_use_global_class_level()) { Ref cp = ProfileManager::get_instance()->getc_player_profile()->get_class_profile(gets_entity_data()->get_id()); if (cp.is_valid()) { int leveldiff = cp->get_level() - _s_class_level; sets_class_level(cp->get_level()); if (leveldiff > 0) { sclass_levelup(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()); for (int i = 0; i < Stat::STAT_ID_TOTAL_STATS; ++i) { cc->get_stat_data()->get_stat_for_stat(_stats[i]); } for (int i = 0; i < Stat::STAT_ID_TOTAL_STATS; ++i) { Ref s = _stats[i]; s->apply_modifiers(); s->setc_values(s->gets_current(), s->gets_max()); s->set_dirty(false); } for (int i = 0; i < cc->get_num_auras(); ++i) { Ref a = cc->get_aura(i); if (a.is_valid()) { a->sapply_simple(this, this, 1.0); } } _s_entity_data->setup_resources(this); sets_entity_data_id(_s_entity_data->get_id()); sets_entity_type(_s_entity_data->get_entity_type()); 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) { adds_spell(cd->get_start_spell(i)); } } for (int i = 0; i < _s_entity_data->get_num_craft_recipes(); ++i) { adds_craft_recipe(_s_entity_data->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 < ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX; ++i) { Ref ii = eqd->get_item(i); if (ii.is_valid()) _s_equipment[i] = ii; } } for (int i = 0; i < _s_resources.size(); ++i) { Ref res = _s_resources.get(i); ERR_CONTINUE(!res.is_valid()); res->resolve_references(); } for (int i = 0; i < _c_resources.size(); ++i) { Ref res = _c_resources.get(i); ERR_CONTINUE(!res.is_valid()); res->resolve_references(); } 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()); } scharacter_levelup(info->get_character_level() - 1); sclass_levelup(info->get_class_level() - 1); sets_class_xp(info->get_class_xp()); sets_character_xp(info->get_character_xp()); if (EntityDataManager::get_instance()->get_allow_class_spell_learning()) { Ref class_profile = ProfileManager::get_instance()->getc_player_profile()->get_class_profile(_s_entity_data->get_id()); 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) { adds_spell_id(spells.get(i)); } } } if (EntityDataManager::get_instance()->get_allow_class_recipe_learning()) { Ref class_profile = ProfileManager::get_instance()->getc_player_profile()->get_class_profile(_s_entity_data->get_id()); 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) { adds_craft_recipe_id(recipes.get(i)); } } } } void Entity::setup_actionbars() { if (!gets_entity_data().is_valid()) return; if (is_deserialized()) { return; } //ProfileManager *pm = ProfileManager::get_instance(); //if (pm != NULL) { // Ref cp = pm->get_class_profile(gets_entity_data()->get_id()); // if (cp.is_valid()) { // set_actionbar_locked(cp->get_actionbar_locked()); // _action_bar_profile = cp->get_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::gets_pet_owner() { return _s_pet_owner; } void Entity::sets_pet_owner(Entity *entity) { _s_pet_owner = entity; } void Entity::sets_pet_owner_bind(Node *entity) { if (!entity) { return; } Entity *e = cast_to(entity); if (!e) { return; } return sets_pet_owner(e); } int Entity::gets_pet_formation_index() { return _s_pet_formation_index; } void Entity::sets_pet_formation_index(int value) { _s_pet_formation_index = value; } EntityEnums::AIStates Entity::gets_pet_ai_state() { return _s_pet_ai_state; } void Entity::sets_pet_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; } 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::adds_pet(Entity *entity) { #if VERSION_MAJOR < 4 ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); #else ERR_FAIL_COND(entity == NULL); #endif //the owner always want to see his pet, and you pet will always want to see the owner adds_sees(entity); entity->adds_sees(this); entity->sets_pet_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->sets_pet_formation_index(_s_pets.size()); //full callback stack spet_added } void Entity::adds_pet_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); adds_pet(e); } Entity *Entity::gets_pet(int index) { ERR_FAIL_INDEX_V(index, _s_pets.size(), NULL); return _s_pets.get(index); } void Entity::removes_pet_index(int index) { ERR_FAIL_INDEX(index, _s_pets.size()); Entity *entity = _s_pets.get(index); _s_pets.remove(index); removes_sees(entity); for (int i = 0; i < _s_pets.size(); ++i) { Entity *pet = _s_pets.get(index); #if VERSION_MAJOR < 4 ERR_CONTINUE(!ObjectDB::instance_validate(pet)); #else ERR_CONTINUE(pet == NULL); #endif _s_pets.get(i)->sets_pet_formation_index(i); } #if VERSION_MAJOR < 4 ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); #else ERR_FAIL_COND(entity == NULL); #endif entity->sets_pet_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::removes_pet(Entity *entity) { for (int i = 0; i < _s_pets.size(); ++i) { if (_s_pets.get(i) == entity) { removes_pet_index(i); return; } } } void Entity::removes_pet_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); removes_pet(e); } int Entity::gets_pet_count() { return _s_pets.size(); } void Entity::addc_pet_path(NodePath path) { Node *n = get_node_or_null(path); Entity *entity = Object::cast_to(n); #if VERSION_MAJOR < 4 ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); #else ERR_FAIL_COND(entity == NULL); #endif addc_pet(entity); } void Entity::addc_pet(Entity *entity) { #if VERSION_MAJOR < 4 ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); #else ERR_FAIL_COND(entity == NULL); #endif _c_pets.push_back(entity); //full callback stack spet_added } void Entity::addc_pet_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); addc_pet(e); } Entity *Entity::getc_pet(int index) { ERR_FAIL_INDEX_V(index, _c_pets.size(), NULL); return _c_pets.get(index); } void Entity::removec_pet_index(int index) { ERR_FAIL_INDEX(index, _c_pets.size()); //Entity *entity = _c_pets.get(index); _c_pets.remove(index); //#if VERSION_MAJOR < 4 //ERR_FAIL_COND(!ObjectDB::instance_validate(entity)); //#else //ERR_FAIL_COND(entity == NULL); //#endif //full callback stack spet_added } void Entity::removec_pet(Entity *entity) { for (int i = 0; i < _c_pets.size(); ++i) { if (_c_pets.get(i) == entity) { removec_pet_index(i); return; } } } void Entity::removec_pet_bind(Node *entity) { Entity *e = Object::cast_to(entity); ERR_FAIL_COND(!e); removec_pet(e); } int Entity::getc_pet_count() { return _s_pets.size(); } //// Profiles //// Ref Entity::get_class_profile() { return ProfileManager::get_instance()->getc_player_profile()->get_class_profile(_s_class_id); } //// 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; //// PlayerData //// dict["guid"] = _s_guid; //dict["entity_data_id"] = _s_class_id; dict["type"] = _s_type; dict["gender"] = _s_gender; dict["class_level"] = gets_class_level(); dict["class_xp"] = gets_class_xp(); dict["character_level"] = _s_character_level; dict["character_xp"] = _s_character_xp; dict["money"] = _s_money; dict["seed"] = _s_seed; if (_s_entity_data.is_valid()) dict["entity_data_id"] = _s_entity_data->get_id(); else dict["entity_data_id"] = 0; //dict["send_flag"] = _s_send_flag; dict["entity_name"] = _s_entity_name; //// Stats //// Dictionary sd; for (int i = 0; i < Stat::STAT_ID_TOTAL_STATS; ++i) { Ref s = _stats[i]; sd[i] = s->to_dict(); } dict["stats"] = sd; //// Equipment //// Dictionary equipment; for (int i = 0; i < ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX; ++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; dict["entity_type"] = _s_entity_type; dict["immunity_flags"] = _s_immunity_flags; dict["entity_flags"] = _s_entity_flags; dict["entity_controller"] = _s_entity_controller; //// Cooldowns //// Dictionary cds; for (int i = 0; i < _s_cooldowns.size(); ++i) { cds[i] = _s_cooldowns.get(i)->to_dict(); } dict["cooldowns"] = cds; Dictionary ccds; for (int i = 0; i < _s_category_cooldowns.size(); ++i) { ccds[i] = _s_category_cooldowns.get(i)->to_dict(); } dict["category_cooldowns"] = ccds; dict["active_category_cooldowns"] = _s_active_category_cooldowns; //// Talents //// dict["free_talent_points"] = _s_free_talent_points; dict["talents"] = _s_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_id(); } dict["known_recipes"] = known_recipes; //// Known Spells //// if (EntityDataManager::get_instance()->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_id(); } 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; //dict["actionbar_profile"] = _action_bar_profile->to_dict(); return dict; } void Entity::_from_dict(const Dictionary &dict) { ERR_FAIL_COND(dict.empty()); sets_entity_type((EntityEnums::EntityType)((int)dict.get("type", 0))); sets_gender(static_cast(static_cast(dict.get("gender", 0)))); if (EntityDataManager::get_instance()->get_use_global_class_level()) { _s_class_level = (dict.get("class_level", 0)); _s_class_xp = (dict.get("class_xp", 0)); } else { sets_class_level(dict.get("class_level", 0)); sets_class_xp(dict.get("class_xp", 0)); } sets_character_level(dict.get("character_level", 0)); sets_character_xp(dict.get("character_xp", 0)); sets_money(dict.get("money", 0)); sets_entity_name(dict.get("entity_name", "")); sets_seed(dict.get("seed", _s_seed)); //// Stats //// Dictionary stats = dict.get("stats", Dictionary()); for (int i = 0; i < Stat::STAT_ID_TOTAL_STATS; ++i) { Ref s = _stats[i]; s->from_dict(stats.get(String::num(i), Dictionary())); } //// Equipment //// Dictionary equipment = dict.get("equipment", Dictionary()); for (int i = 0; i < ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX; ++i) { if (equipment.has(String::num(i))) { Ref ii = _s_equipment[i]; if (!ii.is_valid()) { ii.instance(); } ii->from_dict(dict[String::num(i)]); _s_equipment[i] = ii; _c_equipment[i] = ii; } } //// Resources //// _s_resources.clear(); _c_resources.clear(); Dictionary rd = dict.get("resources", Dictionary()); for (int i = 0; i < rd.size(); ++i) { Dictionary ird = rd.get(String::num(i), Dictionary()); int data_id = ird.get("data_id", 0); Ref resd = EntityDataManager::get_instance()->get_entity_resource(data_id); ERR_CONTINUE(!resd.is_valid()); Ref res = resd->get_entity_resource_instance(); ERR_CONTINUE(!res.is_valid()); res->from_dict(ird); adds_resource(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; //// 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); } sets_entity_type((EntityEnums::EntityType)((int)dict.get("entity_type", 0))); 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); //// Cooldowns //// _s_cooldowns.clear(); _c_cooldowns.clear(); Dictionary cds = dict.get("cooldowns", Dictionary()); for (int i = 0; i < cds.size(); ++i) { Ref cd; cd.instance(); cd->from_dict(cds.get(String::num(i), Dictionary())); _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) { Ref ccd; ccd.instance(); ccd->from_dict(ccds.get(String::num(i), Dictionary())); _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; //// Talents //// _s_free_talent_points = dict.get("free_talent_points", 0); _c_free_talent_points = _s_free_talent_points; Vector talents = dict.get("talents", Vector()); for (int i = 0; i < talents.size(); ++i) { adds_talent(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) { int crid = known_recipes.get(String::num(i), 0); if (EntityDataManager::get_instance() != NULL) { Ref cr = EntityDataManager::get_instance()->get_craft_data(crid); if (cr.is_valid()) { adds_craft_recipe(cr); } } } //// Known Spells //// if (EntityDataManager::get_instance()->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) { int spell_id = known_spells.get(String::num(i), 0); if (EntityDataManager::get_instance() != NULL) { Ref sp = EntityDataManager::get_instance()->get_spell(spell_id); 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); //_action_bar_profile->from_dict(dict.get("actionbar_profile", Dictionary())); int edi = dict.get("entity_data_id", 0); if (EntityDataManager::get_instance() != NULL) { sets_entity_data(EntityDataManager::get_instance()->get_entity_data(edi)); } sets_entity_data_id(edi); } ////// Stat System ////// bool Entity::gets_is_dead() { return _s_is_dead; } bool Entity::getc_is_dead() { return _c_is_dead; } bool Entity::getc_has_global_cooldown() { return _c_gcd >= 0.000000001; } bool Entity::gets_has_global_cooldown() { return _s_gcd >= 0.000000001; } bool Entity::getc_global_cooldown() { return _c_gcd; } bool Entity::gets_global_cooldown() { return _s_gcd; } void Entity::sstart_global_cooldown(float value) { _s_gcd = value; void son_gcd_started(); emit_signal("sgcd_started", _s_gcd); ORPC(cstart_global_cooldown, value); } void Entity::cstart_global_cooldown(float value) { _c_gcd = value; void con_gcd_started(); emit_signal("cgcd_started", _c_gcd); } //// 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)); } } //// Crafting System //// void Entity::crequest_craft(int id) { scraft(id); } void Entity::scraft(int id) { if (has_method("_scraft")) { call("_scraft", id); } } bool Entity::hass_craft_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::hass_craft_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::adds_craft_recipe(Ref craft_recipe) { ERR_FAIL_COND(!craft_recipe.is_valid()); if (hass_craft_recipe(craft_recipe)) return; _s_craft_recipes.push_back(craft_recipe); emit_signal("scraft_recipe_added", this, craft_recipe); ORPC(addc_craft_recipe_id, craft_recipe->get_id()); } void Entity::adds_craft_recipe_id(int id) { ERR_FAIL_COND(!EntityDataManager::get_instance()); if (hass_craft_recipe_id(id)) return; Ref craft_recipe = EntityDataManager::get_instance()->get_craft_data(id); ERR_FAIL_COND(!craft_recipe.is_valid()); _s_craft_recipes.push_back(craft_recipe); if (EntityDataManager::get_instance()->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_instance()->getc_player_profile()->get_class_profile(_s_entity_data->get_id()); 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] == id) { found = true; break; } } if (!found) { recipes.push_back(id); class_profile->set_custom_data("recipes", recipes); } } else { Vector recipes; recipes.push_back(id); class_profile->set_custom_data("recipes", recipes); } } emit_signal("scraft_recipe_added", this, craft_recipe); ORPC(addc_craft_recipe_id, id); } void Entity::removes_craft_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("scraft_recipe_removed", this, craft_recipe); ORPC(removec_craft_recipe, craft_recipe); } void Entity::removes_craft_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("scraft_recipe_removed", this, craft_recipe); ORPC(removec_craft_recipe_id, id); } Ref Entity::gets_craft_recipe(int index) { ERR_FAIL_INDEX_V(index, _s_craft_recipes.size(), Ref()); return _s_craft_recipes.get(index); } Ref Entity::gets_craft_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::gets_craft_recipe_count() { return _s_craft_recipes.size(); } bool Entity::hasc_craft_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::hasc_craft_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::addc_craft_recipe(Ref craft_recipe) { if (hasc_craft_recipe(craft_recipe)) return; _c_craft_recipes.push_back(craft_recipe); emit_signal("ccraft_recipe_added", this, craft_recipe); } void Entity::addc_craft_recipe_id(int id) { ERR_FAIL_COND(!EntityDataManager::get_instance()); if (hasc_craft_recipe_id(id)) return; Ref craft_recipe = EntityDataManager::get_instance()->get_craft_data(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::removec_craft_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::removec_craft_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::getc_craft_recipe(int index) { ERR_FAIL_INDEX_V(index, _c_craft_recipes.size(), Ref()); return _c_craft_recipes.get(index); } int Entity::getc_craft_recipe_count() { return _c_craft_recipes.size(); } //// Stat System //// Ref Entity::get_stat_int(int index) { return _stats[index]; } void Entity::set_stat_int(int index, Ref entry) { _stats[index] = Ref(entry); } Ref Entity::get_stat_enum(Stat::StatId stat_id) { ERR_FAIL_INDEX_V(stat_id, Stat::STAT_ID_TOTAL_STATS, Ref()); return _stats[stat_id]; } void Entity::set_stat_enum(Stat::StatId stat_id, Ref entry) { ERR_FAIL_COND(!entry.is_valid()); //ERR_FAIL_COND(stat_id == Stat::STAT_ID_NONE); if (stat_id == Stat::STAT_ID_NONE) { print_error("Add fail cond here, stat has STAT_ID_NONE!"); _stats[0] = Ref(entry); return; } _stats[stat_id] = Ref(entry); } void Entity::sdie() { //serverside son_death(); //send an event to client VRPC(cdie); //signal emit_signal("sdied", this); } void Entity::cdie() { con_death(); emit_signal("cdied", this); } void Entity::ons_stat_changed(Ref stat) { for (int i = 0; i < _s_resources.size(); ++i) { _s_resources.get(i)->ons_stat_changed(stat); } } void Entity::onc_stat_changed(Ref stat) { for (int i = 0; i < _c_resources.size(); ++i) { _c_resources.get(i)->onc_stat_changed(stat); } } void Entity::ssend_stat(int id, int ccurrent, int cmax) { ERR_FAIL_INDEX(id, Stat::STAT_ID_TOTAL_STATS); if (id <= Stat::STAT_ID_MANA) { VRPC(creceive_stat, id, ccurrent, cmax); return; } ORPC(creceive_stat, id, ccurrent, cmax); } void Entity::creceive_stat(int id, int ccurrent, int cmax) { ERR_FAIL_INDEX(id, Stat::STAT_ID_TOTAL_STATS); _stats[id]->setc_values(ccurrent, cmax); } //// Equip Slots //// bool Entity::should_deny_equip(ItemEnums::EquipSlots equip_slot, Ref item) { if (_s_entity_data.is_valid()) { if (_s_entity_data->should_deny_equip(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()->should_deny_equip(ad, equip_slot, item)) return true; } if (has_method("_should_deny_equip")) if (call("_should_deny_equip", equip_slot, item)) return true; return false; } void Entity::son_equip_success(ItemEnums::EquipSlots equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_data.is_valid()) { _s_entity_data->son_equip_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()->son_equip_success(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_son_equip_success")) call("_son_equip_success", equip_slot, item, old_item, bag_slot); emit_signal("son_equip_success", this, equip_slot, item, old_item, bag_slot); } void Entity::son_equip_fail(ItemEnums::EquipSlots equip_slot, Ref item, Ref old_item, int bag_slot) { if (_s_entity_data.is_valid()) { _s_entity_data->son_equip_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()->son_equip_fail(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_son_equip_fail")) call("_son_equip_fail", equip_slot, item, old_item, bag_slot); emit_signal("son_equip_fail", this, equip_slot, item, old_item, bag_slot); } void Entity::con_equip_success(ItemEnums::EquipSlots equip_slot, Ref item, Ref old_item, int bag_slot) { if (_c_entity_data.is_valid()) { _c_entity_data->con_equip_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()->con_equip_success(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_con_equip_success")) call("_con_equip_success", equip_slot, item, old_item, bag_slot); emit_signal("con_equip_success", this, equip_slot, item, old_item, bag_slot); } void Entity::con_equip_fail(ItemEnums::EquipSlots equip_slot, Ref item, Ref old_item, int bag_slot) { if (_c_entity_data.is_valid()) { _c_entity_data->con_equip_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()->con_equip_fail(ad, equip_slot, item, old_item, bag_slot); } if (has_method("_con_equip_fail")) call("_con_equip_fail", equip_slot, item, old_item, bag_slot); emit_signal("con_equip_fail", this, equip_slot, item, old_item, bag_slot); } void Entity::crequest_equip(ItemEnums::EquipSlots equip_slot, int bag_slot) { RPCS(sequip, equip_slot, bag_slot) } void Entity::sequip(ItemEnums::EquipSlots equip_slot, int bag_slot) { call("_sequip", equip_slot, bag_slot); } void Entity::_sequip(ItemEnums::EquipSlots equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX); ERR_FAIL_COND(!_s_bag.is_valid()); Ref bag_item = _s_bag->get_item(bag_slot); Ref equipped_item = gets_equip_slot(equip_slot); if (!can_equip_item(equip_slot, bag_item)) { ORPC(cequip_fail, equip_slot, bag_slot); return; } if (should_deny_equip(equip_slot, bag_item)) { ORPC(cequip_fail, equip_slot, bag_slot); return; } //check armor type //check required skills if (equipped_item.is_valid()) sdeapply_item(equipped_item); if (bag_item.is_valid()) sapply_item(bag_item); sets_equip_slot(equip_slot, bag_item); _s_bag->add_item_at(equip_slot, equipped_item, false); ORPC(cequip_success, equip_slot, bag_slot); } void Entity::cequip_success(ItemEnums::EquipSlots equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX); ERR_FAIL_COND(!_c_bag.is_valid()); Ref old_bag_item = _c_bag->get_item(bag_slot); Ref old_equipped_item = getc_equip_slot(equip_slot); _c_bag->add_item_at(bag_slot, old_equipped_item); setc_equip_slot(equip_slot, old_bag_item); if (old_equipped_item.is_valid()) cdeapply_item(old_equipped_item); if (old_bag_item.is_valid()) capply_item(old_bag_item); con_equip_success(equip_slot, old_bag_item, old_equipped_item, bag_slot); } void Entity::cequip_fail(ItemEnums::EquipSlots equip_slot, int bag_slot) { ERR_FAIL_INDEX(equip_slot, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX); ERR_FAIL_COND(!_c_bag.is_valid()); Ref bag_item = _c_bag->get_item(bag_slot); Ref equipped_item = getc_equip_slot(equip_slot); con_equip_fail(equip_slot, equipped_item, bag_item, bag_slot); } Ref Entity::gets_equip_slot(int index) { ERR_FAIL_INDEX_V(index, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX, Ref()); return _s_equipment[index]; } void Entity::sets_equip_slot(int index, Ref item) { ERR_FAIL_INDEX(index, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX); _s_equipment[index] = item; } Ref Entity::getc_equip_slot(int index) { ERR_FAIL_INDEX_V(index, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX, Ref()); return _c_equipment[index]; } void Entity::setc_equip_slot(int index, Ref item) { ERR_FAIL_INDEX(index, ItemEnums::EQUIP_SLOT_EQUIP_SLOT_MAX); _c_equipment[index] = item; } bool Entity::can_equip_item(ItemEnums::EquipSlots equip_slot, Ref item) { return call("_can_equip_item", equip_slot, item); } bool Entity::_can_equip_item(ItemEnums::EquipSlots 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::sapply_item(Ref item) { call("_sapply_item", item); } void Entity::sdeapply_item(Ref item) { call("_sdeapply_item", item); } void Entity::_sapply_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->get_item_stat_modifier_count(); ++i) { Ref mod = item->get_item_stat_modifier(i); if (!mod.is_valid()) continue; Ref stat = get_stat_enum(mod->get_stat_id()); ERR_CONTINUE(!stat.is_valid()); Ref sm = stat->get_modifier(0); ERR_CONTINUE(!sm.is_valid()); sm->set_base_mod(sm->get_base_mod() + mod->get_base_mod()); sm->set_bonus_mod(sm->get_bonus_mod() + mod->get_bonus_mod()); sm->set_percent_mod(sm->get_percent_mod() + mod->get_percent_mod()); } } void Entity::_sdeapply_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->get_item_stat_modifier_count(); ++i) { Ref mod = item->get_item_stat_modifier(i); if (!mod.is_valid()) continue; Ref stat = get_stat_enum(mod->get_stat_id()); ERR_CONTINUE(!stat.is_valid()); Ref sm = stat->get_modifier(0); ERR_CONTINUE(!sm.is_valid()); sm->set_base_mod(sm->get_base_mod() - mod->get_base_mod()); sm->set_bonus_mod(sm->get_bonus_mod() - mod->get_bonus_mod()); sm->set_percent_mod(sm->get_percent_mod() - mod->get_percent_mod()); } } void Entity::capply_item(Ref item) { call("_capply_item", item); } void Entity::cdeapply_item(Ref item) { call("_cdeapply_item", item); } void Entity::_capply_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); #if VERSION_MAJOR < 4 if (it->get_item_visual().is_valid() && ObjectDB::instance_validate(_character_skeleton)) { #else if (it->get_item_visual().is_valid() && _character_skeleton == NULL) { #endif if (_character_skeleton->has_method("add_item_visual")) _character_skeleton->call("add_item_visual", it->get_item_visual()); } } void Entity::_cdeapply_item(Ref item) { ERR_FAIL_COND(!item.is_valid()); Ref it = item->get_item_template(); ERR_FAIL_COND(!it.is_valid()); #if VERSION_MAJOR < 4 if (it->get_item_visual().is_valid() && ObjectDB::instance_validate(_character_skeleton)) { #else if (it->get_item_visual().is_valid() && _character_skeleton == NULL) { #endif if (_character_skeleton->has_method("remove_item_visual")) _character_skeleton->call("remove_item_visual", it->get_item_visual()); } } //// Resources //// Ref Entity::gets_resource_index(int index) { ERR_FAIL_INDEX_V(index, _s_resources.size(), Ref()); return _s_resources.get(index); } Ref Entity::gets_resource_id(int id) { for (int i = 0; i < _s_resources.size(); ++i) { Ref r = _s_resources.get(i); if (r->get_data_id() == id) { return r; } } return Ref(); } void Entity::adds_resource(Ref resource) { ERR_FAIL_COND(!resource.is_valid()); _s_resources.push_back(resource); resource->ons_added(this); son_entity_resource_added(resource); VRPCOBJP(addc_resource_rpc, _s_resources.size() - 1, JSON::print(resource->to_dict()), addc_resource, _s_resources.size() - 1, resource); } int Entity::gets_resource_count() { return _s_resources.size(); } void Entity::removes_resource(int index) { ERR_FAIL_INDEX(index, _s_resources.size()); Ref res = _s_resources.get(index); _s_resources.remove(index); son_entity_resource_removed(res); VRPC(removec_resource, index); } void Entity::clears_resource() { _s_resources.clear(); VRPC(clearc_resource); } void Entity::addc_resource_rpc(int index, String data) { //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