/*************************************************************************/ /* entity.cpp */ /*************************************************************************/ /* This file is part of: */ /* PANDEMONIUM ENGINE */ /* https://github.com/Relintai/pandemonium_engine */ /*************************************************************************/ /* Copyright (c) 2022-present Péter Magyar. */ /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* */ /* 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/main/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::character_skeleton_path_get() { return _character_skeleton_path; } void Entity::character_skeleton_path_set(NodePath value) { _character_skeleton_path = value; character_skeleton_set(get_node_or_null(_character_skeleton_path)); } Node *Entity::character_skeleton_get() { return _character_skeleton; } void Entity::character_skeleton_set(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::entity_data_id_gets() { return _s_class_id; } void Entity::entity_data_id_sets(int value) { _s_class_id = value; } int Entity::entity_data_id_getc() { return _c_class_id; } void Entity::entity_data_id_setc(int value) { _c_class_id = value; if (_c_class_id == 0) { entity_data_setc(Ref()); return; } if (ESS::get_singleton() != NULL) { entity_data_setc(ESS::get_singleton()->get_resource_db()->get_entity_data(_c_class_id)); } } StringName Entity::entity_data_path_gets() { return _s_entity_data_path; } void Entity::entity_data_path_sets(const StringName &value) { _s_entity_data_path = value; } Ref Entity::entity_data_gets() { return _s_entity_data; } void Entity::entity_data_sets(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(entity_data_id_setc, _s_class_id); } Ref Entity::entity_data_getc() { return _c_entity_data; } void Entity::entity_data_setc(Ref value) { _c_entity_data = value; body_instance(value, _c_model_index); emit_signal("centity_data_changed", value); } EntityEnums::AIStates Entity::ai_state_gets() const { return _sai_state; } void Entity::ai_state_sets(EntityEnums::AIStates state) { _sai_state = state; } EntityEnums::AIStates Entity::ai_state_stored_gets() const { return _sai_state_stored; } void Entity::ai_state_stored_sets(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()); } original_entity_controller_sets(info->get_entity_controller()); entity_controller_sets(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 { entity_data_sets(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 = entity_data_gets()->get_entity_class_data(); ERR_FAIL_COND(!cc.is_valid()); //Ref stat_data = _s_entity_data->get_stat_data(); ai_sets(_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(entity_data_gets()->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(!entity_data_gets().is_valid()); Ref cc = entity_data_gets()->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); entity_data_id_sets(_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) { // original_entity_controller_sets(_s_entity_data->get_entity_controller()); // entity_controller_sets(_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; } } ai_sets(_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 (!entity_data_gets().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 (!bag_gets().is_valid()) { Ref bag; bag.instance(); bag->set_size(entity_data_gets()->get_bag_size()); bag_sets(bag); } } // AI bool Entity::pet_gets_is() { return _s_pet_owner; } bool Entity::pet_getc_is() { 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_ai_state_gets() { return _s_pet_ai_state; } void Entity::pet_ai_state_sets(EntityEnums::AIStates value) { _s_pet_ai_state = value; } EntityEnums::EntityController Entity::original_entity_controller_gets() { return _s_entity_controller; } void Entity::original_entity_controller_sets(EntityEnums::EntityController value) { _s_entity_controller = value; } EntityEnums::EntityController Entity::entity_controller_gets() { return _s_entity_controller; } void Entity::entity_controller_sets(EntityEnums::EntityController value) { _s_entity_controller = value; ORPC(entity_controller_setc, value); } EntityEnums::EntityController Entity::entity_controller_getc() { return _s_entity_controller; } void Entity::entity_controller_setc(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::ai_gets() { return _s_ai; } void Entity::ai_sets(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->ai_state_stored_sets(entity->ai_state_gets()); entity->ai_state_sets(_s_pet_ai_state); entity->entity_controller_sets(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->ai_state_sets(entity->ai_state_stored_gets()); entity->entity_controller_sets(entity->original_entity_controller_gets()); //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))); //original_entity_controller_sets(contr); //entity_controller_sets(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()) { spell_points_sets_free(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); bag_sets(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) { entity_data_sets(ESS::get_singleton()->get_resource_db()->get_entity_data_path(edp)); } entity_data_path_sets(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::state_gets() { return _s_state; } void Entity::state_sets(int state) { _s_state = state; emit_signal("sstate_changed", state); VRPC(state_setc, state); } int Entity::state_getc() { return _c_state; } void Entity::state_setc(int state) { _c_state = state; emit_signal("cstate_changed", state); } void Entity::state_ref_adds(int state_index) { ERR_FAIL_INDEX(state_index, EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); if (_s_states[state_index]++ == 0) { state_sets(state_gets() | EntityEnums::get_state_flag_for_index(state_index)); } } void Entity::state_ref_removes(int state_index) { ERR_FAIL_INDEX(state_index, EntityEnums::ENTITY_STATE_TYPE_INDEX_MAX); if (--_s_states[state_index] == 0) { state_sets(state_gets() ^ 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::stat_get(const int stat_id) const { ERR_FAIL_INDEX_V(stat_id, _stats.size(), EntityStat()); return _stats[stat_id]; } void Entity::stat_set(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::stat_ssend(int id, int ccurrent) { ERR_FAIL_INDEX(id, _stats.size()); //Only the owner needs access to stats ORPC(stat_creceive, id, ccurrent); } void Entity::stat_creceive(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