diff --git a/bt/tasks/scene/bt_set_agent_property.cpp b/bt/tasks/scene/bt_set_agent_property.cpp index 16f93df..dc3c87a 100644 --- a/bt/tasks/scene/bt_set_agent_property.cpp +++ b/bt/tasks/scene/bt_set_agent_property.cpp @@ -24,6 +24,11 @@ void BTSetAgentProperty::set_value(Ref p_value) { } } +void BTSetAgentProperty::set_operation(LimboUtility::Operation p_operation) { + operation = p_operation; + emit_changed(); +} + PackedStringArray BTSetAgentProperty::get_configuration_warnings() const { PackedStringArray warnings = BTAction::get_configuration_warnings(); if (property == StringName()) { @@ -48,13 +53,22 @@ BT::Status BTSetAgentProperty::_tick(double p_delta) { ERR_FAIL_COND_V_MSG(property == StringName(), FAILURE, "BTSetAgentProperty: `property` is not set."); ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetAgentProperty: `value` is not set."); + Variant result; StringName error_value = SNAME("ErrorGettingValue"); - Variant v = value->get_value(get_agent(), get_blackboard(), error_value); - ERR_FAIL_COND_V_MSG(v == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter."); - + Variant right_value = value->get_value(get_agent(), get_blackboard(), error_value); + ERR_FAIL_COND_V_MSG(right_value == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter."); bool r_valid; - get_agent()->set(property, v, &r_valid); - ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Couldn't set property \"%s\" with value \"%s\"", property, v)); + if (operation == LimboUtility::OPERATION_NONE) { + result = right_value; + } else { + Variant left_value = get_agent()->get(property, &r_valid); + ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Failed to get agent's \"%s\" property. Returning FAILURE.", property)); + result = LimboUtility::get_singleton()->perform_operation(operation, left_value, right_value); + ERR_FAIL_COND_V_MSG(result == Variant(), FAILURE, "BTSetAgentProperty: Operation not valid. Returning FAILURE."); + } + + get_agent()->set(property, result, &r_valid); + ERR_FAIL_COND_V_MSG(!r_valid, FAILURE, vformat("BTSetAgentProperty: Couldn't set property \"%s\" with value \"%s\"", property, result)); return SUCCESS; } @@ -63,7 +77,10 @@ void BTSetAgentProperty::_bind_methods() { ClassDB::bind_method(D_METHOD("get_property"), &BTSetAgentProperty::get_property); ClassDB::bind_method(D_METHOD("set_value", "p_value"), &BTSetAgentProperty::set_value); ClassDB::bind_method(D_METHOD("get_value"), &BTSetAgentProperty::get_value); + ClassDB::bind_method(D_METHOD("set_operation", "p_operation"), &BTSetAgentProperty::set_operation); + ClassDB::bind_method(D_METHOD("get_operation"), &BTSetAgentProperty::get_operation); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "property"), "set_property", "get_property"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "value", PROPERTY_HINT_RESOURCE_TYPE, "BBVariant"), "set_value", "get_value"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "None,Addition,Subtraction,Multiplication,Division,Modulo,Power,Bitwise Shift Left,Bitwise Shift Right,Bitwise AND,Bitwise OR,Bitwise XOR"), "set_operation", "get_operation"); } diff --git a/bt/tasks/scene/bt_set_agent_property.h b/bt/tasks/scene/bt_set_agent_property.h index 65fff0e..e5a4b12 100644 --- a/bt/tasks/scene/bt_set_agent_property.h +++ b/bt/tasks/scene/bt_set_agent_property.h @@ -15,6 +15,7 @@ #include "../bt_action.h" #include "modules/limboai/blackboard/bb_param/bb_variant.h" +#include "modules/limboai/util/limbo_utility.h" class BTSetAgentProperty : public BTAction { GDCLASS(BTSetAgentProperty, BTAction); @@ -23,6 +24,7 @@ class BTSetAgentProperty : public BTAction { private: StringName property; Ref value; + LimboUtility::Operation operation = LimboUtility::OPERATION_NONE; protected: static void _bind_methods(); @@ -38,6 +40,9 @@ public: void set_value(Ref p_value); Ref get_value() const { return value; } + + void set_operation(LimboUtility::Operation p_operation); + LimboUtility::Operation get_operation() const { return operation; } }; #endif // BT_SET_AGENT_PROPERTY \ No newline at end of file diff --git a/doc_classes/BTSetAgentProperty.xml b/doc_classes/BTSetAgentProperty.xml index 04e92c0..b46cfe0 100644 --- a/doc_classes/BTSetAgentProperty.xml +++ b/doc_classes/BTSetAgentProperty.xml @@ -4,12 +4,16 @@ BT action that assigns a value to the specified agent's property. - BTSetAgentProperty assigns the specified [member value] to the agent's property identified by the [member property] and returns [code]SUCCESS[/code]. + BTSetAgentProperty assigns the specified [member value] to the agent's property identified by the [member property] and returns [code]SUCCESS[/code]. Optionally, it can perform a specific [member operation] before assignment. Returns [code]FAILURE[/code] if it fails to set the property. + + Specifies the operation to be performed before assignment. Operation is executed as follows: + [code]property = property OPERATION value[/code] + Parameter that specifies the agent's property name. diff --git a/tests/test_set_agent_property.h b/tests/test_set_agent_property.h index acb97eb..c9fe1c5 100644 --- a/tests/test_set_agent_property.h +++ b/tests/test_set_agent_property.h @@ -31,10 +31,10 @@ TEST_CASE("[Modules][LimboAI] BTSetAgentProperty") { sap->initialize(agent, bb); sap->set_property("process_priority"); // * property that will be set by the task - Ref value_param = memnew(BBVariant); - value_param->set_value_source(BBParam::SAVED_VALUE); - value_param->set_saved_value(7); - sap->set_value(value_param); + Ref value = memnew(BBVariant); + value->set_value_source(BBParam::SAVED_VALUE); + value->set_saved_value(7); + sap->set_value(value); SUBCASE("With integer") { CHECK(sap->execute(0.01666) == BTTask::SUCCESS); @@ -59,14 +59,14 @@ TEST_CASE("[Modules][LimboAI] BTSetAgentProperty") { ERR_PRINT_ON; } SUBCASE("With StringName and String") { - value_param->set_saved_value("TestName"); + value->set_saved_value("TestName"); sap->set_property("name"); CHECK(sap->execute(0.01666) == BTTask::SUCCESS); CHECK(agent->get_name() == "TestName"); } SUBCASE("With blackboard variable") { - value_param->set_value_source(BBParam::BLACKBOARD_VAR); - value_param->set_variable("priority"); + value->set_value_source(BBParam::BLACKBOARD_VAR); + value->set_variable("priority"); SUBCASE("With proper BB variable") { bb->set_var("priority", 8); @@ -81,19 +81,104 @@ TEST_CASE("[Modules][LimboAI] BTSetAgentProperty") { CHECK(agent->get_process_priority() == 0); } SUBCASE("When BB variable doesn't exist") { - value_param->set_variable("not_found"); + value->set_variable("not_found"); ERR_PRINT_OFF; CHECK(sap->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; CHECK(agent->get_process_priority() == 0); } SUBCASE("When BB variable isn't set") { - value_param->set_variable(""); + value->set_variable(""); ERR_PRINT_OFF; CHECK(sap->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; CHECK(agent->get_process_priority() == 0); } + SUBCASE("When performing an operation") { + agent->set_process_priority(8); + value->set_value_source(BBParam::SAVED_VALUE); + value->set_saved_value(3); + + SUBCASE("Addition") { + sap->set_operation(LimboUtility::OPERATION_ADDITION); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 11); + } + SUBCASE("Subtraction") { + sap->set_operation(LimboUtility::OPERATION_SUBTRACTION); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 5); + } + SUBCASE("Multiplication") { + sap->set_operation(LimboUtility::OPERATION_MULTIPLICATION); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 24); + } + SUBCASE("Division") { + sap->set_operation(LimboUtility::OPERATION_DIVISION); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 2); + } + SUBCASE("Modulo") { + sap->set_operation(LimboUtility::OPERATION_MODULO); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 2); + } + SUBCASE("Power") { + sap->set_operation(LimboUtility::OPERATION_POWER); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 512); + } + SUBCASE("Bitwise shift left") { + sap->set_operation(LimboUtility::OPERATION_BIT_SHIFT_LEFT); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 64); + } + SUBCASE("Bitwise shift right") { + sap->set_operation(LimboUtility::OPERATION_BIT_SHIFT_RIGHT); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 1); + } + SUBCASE("Bitwise AND") { + agent->set_process_priority(6); + sap->set_operation(LimboUtility::OPERATION_BIT_AND); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 2); + } + SUBCASE("Bitwise OR") { + agent->set_process_priority(6); + sap->set_operation(LimboUtility::OPERATION_BIT_OR); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 7); + } + SUBCASE("Bitwise XOR") { + agent->set_process_priority(6); + sap->set_operation(LimboUtility::OPERATION_BIT_XOR); + CHECK(sap->execute(0.01666) == BTTask::SUCCESS); + CHECK(agent->get_process_priority() == 5); + } + } + SUBCASE("Performing an operation when assigned variable doesn't exist.") { + sap->set_property("not_found"); + value->set_value_source(BBParam::SAVED_VALUE); + value->set_saved_value(3); + sap->set_operation(LimboUtility::OPERATION_ADDITION); + + ERR_PRINT_OFF; + CHECK(sap->execute(0.01666) == BTTask::FAILURE); + ERR_PRINT_ON; + } + SUBCASE("Performing an operation with incompatible operand types.") { + agent->set_process_priority(2); + value->set_value_source(BBParam::SAVED_VALUE); + value->set_saved_value("3"); // String + sap->set_operation(LimboUtility::OPERATION_ADDITION); + + ERR_PRINT_OFF; + CHECK(sap->execute(0.01666) == BTTask::FAILURE); + ERR_PRINT_ON; + CHECK(agent->get_process_priority() == 2); + } } memdelete(agent);