godot/modules/visual_script/visual_script_flow_control.cpp
Juan Linietsky 118eed485e ObjectTypeDB was renamed to ClassDB. Types are meant to be more generic to Variant.
All usages of "type" to refer to classes were renamed to "class"
ClassDB has been exposed to GDScript.
OBJ_TYPE() macro is now GDCLASS()
2017-01-02 23:03:46 -03:00

1941 lines
45 KiB
C++

#include "visual_script_flow_control.h"
#include "os/keyboard.h"
#include "globals.h"
//////////////////////////////////////////
////////////////RETURN////////////////////
//////////////////////////////////////////
int VisualScriptReturn::get_output_sequence_port_count() const {
return 0;
}
bool VisualScriptReturn::has_input_sequence_port() const{
return true;
}
int VisualScriptReturn::get_input_value_port_count() const{
return with_value?1:0;
}
int VisualScriptReturn::get_output_value_port_count() const{
return 0;
}
String VisualScriptReturn::get_output_sequence_port_text(int p_port) const {
return String();
}
PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const{
PropertyInfo pinfo;
pinfo.name="result";
pinfo.type=type;
return pinfo;
}
PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const{
return PropertyInfo();
}
String VisualScriptReturn::get_caption() const {
return "Return";
}
String VisualScriptReturn::get_text() const {
return get_name();
}
void VisualScriptReturn::set_return_type(Variant::Type p_type) {
if (type==p_type)
return;
type=p_type;
ports_changed_notify();
}
Variant::Type VisualScriptReturn::get_return_type() const{
return type;
}
void VisualScriptReturn::set_enable_return_value(bool p_enable) {
if (with_value==p_enable)
return;
with_value=p_enable;
ports_changed_notify();
}
bool VisualScriptReturn::is_return_value_enabled() const {
return with_value;
}
void VisualScriptReturn::_bind_methods() {
ClassDB::bind_method(_MD("set_return_type","type"),&VisualScriptReturn::set_return_type);
ClassDB::bind_method(_MD("get_return_type"),&VisualScriptReturn::get_return_type);
ClassDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value);
ClassDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled);
String argt="Any";
for(int i=1;i<Variant::VARIANT_MAX;i++) {
argt+=","+Variant::get_type_name(Variant::Type(i));
}
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),_SCS("set_enable_return_value"),_SCS("is_return_value_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),_SCS("set_return_type"),_SCS("get_return_type"));
}
class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance {
public:
VisualScriptReturn *node;
VisualScriptInstance *instance;
bool with_value;
virtual int get_working_memory_size() const { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (with_value) {
*p_working_mem = *p_inputs[0];
} else {
*p_working_mem = Variant();
}
return 0;
}
};
VisualScriptNodeInstance* VisualScriptReturn::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceReturn * instance = memnew(VisualScriptNodeInstanceReturn );
instance->node=this;
instance->instance=p_instance;
instance->with_value=with_value;
return instance;
}
VisualScriptReturn::VisualScriptReturn() {
with_value=false;
type=Variant::NIL;
}
template<bool with_value>
static Ref<VisualScriptNode> create_return_node(const String& p_name) {
Ref<VisualScriptReturn> node;
node.instance();
node->set_enable_return_value(with_value);
return node;
}
//////////////////////////////////////////
////////////////CONDITION/////////////////
//////////////////////////////////////////
int VisualScriptCondition::get_output_sequence_port_count() const {
return 3;
}
bool VisualScriptCondition::has_input_sequence_port() const{
return true;
}
int VisualScriptCondition::get_input_value_port_count() const{
return 1;
}
int VisualScriptCondition::get_output_value_port_count() const{
return 0;
}
String VisualScriptCondition::get_output_sequence_port_text(int p_port) const {
if (p_port==0)
return "true";
else if (p_port==1)
return "false";
else
return "done";
}
PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const{
PropertyInfo pinfo;
pinfo.name="cond";
pinfo.type=Variant::BOOL;
return pinfo;
}
PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const{
return PropertyInfo();
}
String VisualScriptCondition::get_caption() const {
return "Condition";
}
String VisualScriptCondition::get_text() const {
return "if (cond) is: ";
}
void VisualScriptCondition::_bind_methods() {
}
class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance {
public:
VisualScriptCondition *node;
VisualScriptInstance *instance;
//virtual int get_working_memory_size() const { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (p_start_mode==START_MODE_CONTINUE_SEQUENCE)
return 2;
else if (p_inputs[0]->operator bool())
return 0 | STEP_FLAG_PUSH_STACK_BIT;
else
return 1 | STEP_FLAG_PUSH_STACK_BIT;
}
};
VisualScriptNodeInstance* VisualScriptCondition::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceCondition * instance = memnew(VisualScriptNodeInstanceCondition );
instance->node=this;
instance->instance=p_instance;
return instance;
}
VisualScriptCondition::VisualScriptCondition() {
}
//////////////////////////////////////////
////////////////WHILE/////////////////
//////////////////////////////////////////
int VisualScriptWhile::get_output_sequence_port_count() const {
return 2;
}
bool VisualScriptWhile::has_input_sequence_port() const{
return true;
}
int VisualScriptWhile::get_input_value_port_count() const{
return 1;
}
int VisualScriptWhile::get_output_value_port_count() const{
return 0;
}
String VisualScriptWhile::get_output_sequence_port_text(int p_port) const {
if (p_port==0)
return "repeat";
else
return "exit";
}
PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const{
PropertyInfo pinfo;
pinfo.name="cond";
pinfo.type=Variant::BOOL;
return pinfo;
}
PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const{
return PropertyInfo();
}
String VisualScriptWhile::get_caption() const {
return "While";
}
String VisualScriptWhile::get_text() const {
return "while (cond): ";
}
void VisualScriptWhile::_bind_methods() {
}
class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance {
public:
VisualScriptWhile *node;
VisualScriptInstance *instance;
//virtual int get_working_memory_size() const { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
bool keep_going = p_inputs[0]->operator bool();
if (keep_going)
return 0|STEP_FLAG_PUSH_STACK_BIT;
else
return 1;
}
};
VisualScriptNodeInstance* VisualScriptWhile::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceWhile * instance = memnew(VisualScriptNodeInstanceWhile );
instance->node=this;
instance->instance=p_instance;
return instance;
}
VisualScriptWhile::VisualScriptWhile() {
}
//////////////////////////////////////////
////////////////ITERATOR/////////////////
//////////////////////////////////////////
int VisualScriptIterator::get_output_sequence_port_count() const {
return 2;
}
bool VisualScriptIterator::has_input_sequence_port() const{
return true;
}
int VisualScriptIterator::get_input_value_port_count() const{
return 1;
}
int VisualScriptIterator::get_output_value_port_count() const{
return 1;
}
String VisualScriptIterator::get_output_sequence_port_text(int p_port) const {
if (p_port==0)
return "each";
else
return "exit";
}
PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const{
PropertyInfo pinfo;
pinfo.name="input";
pinfo.type=Variant::NIL;
return pinfo;
}
PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const{
PropertyInfo pinfo;
pinfo.name="elem";
pinfo.type=Variant::NIL;
return pinfo;
}
String VisualScriptIterator::get_caption() const {
return "Iterator";
}
String VisualScriptIterator::get_text() const {
return "for (elem) in (input): ";
}
void VisualScriptIterator::_bind_methods() {
}
class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance {
public:
VisualScriptIterator *node;
VisualScriptInstance *instance;
virtual int get_working_memory_size() const { return 2; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (p_start_mode==START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0]=*p_inputs[0];
bool valid;
bool can_iter = p_inputs[0]->iter_init(p_working_mem[1],valid);
if (!valid) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str=RTR("Input type not iterable: ")+Variant::get_type_name(p_inputs[0]->get_type());
return 0;
}
if (!can_iter)
return 1; //nothing to iterate
*p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid);
if (!valid) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str=RTR("Iterator became invalid");
return 0;
}
} else { //continue sequence
bool valid;
bool can_iter = p_working_mem[0].iter_next(p_working_mem[1],valid);
if (!valid) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str=RTR("Iterator became invalid: ")+Variant::get_type_name(p_inputs[0]->get_type());
return 0;
}
if (!can_iter)
return 1; //nothing to iterate
*p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid);
if (!valid) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str=RTR("Iterator became invalid");
return 0;
}
}
return 0|STEP_FLAG_PUSH_STACK_BIT; //go around
}
};
VisualScriptNodeInstance* VisualScriptIterator::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceIterator * instance = memnew(VisualScriptNodeInstanceIterator );
instance->node=this;
instance->instance=p_instance;
return instance;
}
VisualScriptIterator::VisualScriptIterator() {
}
//////////////////////////////////////////
////////////////SEQUENCE/////////////////
//////////////////////////////////////////
int VisualScriptSequence::get_output_sequence_port_count() const {
return steps;
}
bool VisualScriptSequence::has_input_sequence_port() const{
return true;
}
int VisualScriptSequence::get_input_value_port_count() const{
return 0;
}
int VisualScriptSequence::get_output_value_port_count() const{
return 1;
}
String VisualScriptSequence::get_output_sequence_port_text(int p_port) const {
return itos(p_port+1);
}
PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const{
return PropertyInfo();
}
PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const{
return PropertyInfo(Variant::INT,"current");
}
String VisualScriptSequence::get_caption() const {
return "Sequence";
}
String VisualScriptSequence::get_text() const {
return "in order: ";
}
void VisualScriptSequence::set_steps(int p_steps) {
ERR_FAIL_COND(p_steps<1);
if (steps==p_steps)
return;
steps=p_steps;
ports_changed_notify();
}
int VisualScriptSequence::get_steps() const {
return steps;
}
void VisualScriptSequence::_bind_methods() {
ClassDB::bind_method(_MD("set_steps","steps"),&VisualScriptSequence::set_steps);
ClassDB::bind_method(_MD("get_steps"),&VisualScriptSequence::get_steps);
ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),_SCS("set_steps"),_SCS("get_steps"));
}
class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance {
public:
VisualScriptSequence *node;
VisualScriptInstance *instance;
int steps;
virtual int get_working_memory_size() const { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (p_start_mode==START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0]=0;
}
int step = p_working_mem[0];
*p_outputs[0]=step;
if (step+1==steps)
return step;
else {
p_working_mem[0]=step+1;
return step|STEP_FLAG_PUSH_STACK_BIT;
}
}
};
VisualScriptNodeInstance* VisualScriptSequence::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceSequence * instance = memnew(VisualScriptNodeInstanceSequence );
instance->node=this;
instance->instance=p_instance;
instance->steps=steps;
return instance;
}
VisualScriptSequence::VisualScriptSequence() {
steps=1;
}
//////////////////////////////////////////
////////////////EVENT TYPE FILTER///////////
//////////////////////////////////////////
int VisualScriptSwitch::get_output_sequence_port_count() const {
return case_values.size()+1;
}
bool VisualScriptSwitch::has_input_sequence_port() const{
return true;
}
int VisualScriptSwitch::get_input_value_port_count() const{
return case_values.size()+1;
}
int VisualScriptSwitch::get_output_value_port_count() const{
return 0;
}
String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
if (p_port==case_values.size())
return "done";
return String();
}
PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const{
if (p_idx<case_values.size()) {
return PropertyInfo(case_values[p_idx].type," =");
} else
return PropertyInfo(Variant::NIL,"input");
}
PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const{
return PropertyInfo();
}
String VisualScriptSwitch::get_caption() const {
return "Switch";
}
String VisualScriptSwitch::get_text() const {
return "'input' is:";
}
class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
int case_count;
//virtual int get_working_memory_size() const { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (p_start_mode==START_MODE_CONTINUE_SEQUENCE) {
return case_count; //exit
}
for(int i=0;i<case_count;i++) {
if (*p_inputs[i]==*p_inputs[case_count]) {
return i|STEP_FLAG_PUSH_STACK_BIT;
}
}
return case_count;
}
};
VisualScriptNodeInstance* VisualScriptSwitch::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceSwitch * instance = memnew(VisualScriptNodeInstanceSwitch );
instance->instance=p_instance;
instance->case_count=case_values.size();
return instance;
}
bool VisualScriptSwitch::_set(const StringName& p_name, const Variant& p_value) {
if (String(p_name)=="case_count") {
case_values.resize(p_value);
_change_notify();
ports_changed_notify();
return true;
}
if (String(p_name).begins_with("case/")) {
int idx = String(p_name).get_slice("/",1).to_int();
ERR_FAIL_INDEX_V(idx,case_values.size(),false);
case_values[idx].type=Variant::Type(int(p_value));
_change_notify();
ports_changed_notify();
return true;
}
return false;
}
bool VisualScriptSwitch::_get(const StringName& p_name,Variant &r_ret) const {
if (String(p_name)=="case_count") {
r_ret=case_values.size();
return true;
}
if (String(p_name).begins_with("case/")) {
int idx = String(p_name).get_slice("/",1).to_int();
ERR_FAIL_INDEX_V(idx,case_values.size(),false);
r_ret=case_values[idx].type;
return true;
}
return false;
}
void VisualScriptSwitch::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT,"case_count",PROPERTY_HINT_RANGE,"0,128"));
String argt="Any";
for(int i=1;i<Variant::VARIANT_MAX;i++) {
argt+=","+Variant::get_type_name(Variant::Type(i));
}
for(int i=0;i<case_values.size();i++) {
p_list->push_back(PropertyInfo(Variant::INT,"case/"+itos(i),PROPERTY_HINT_ENUM,argt));
}
}
void VisualScriptSwitch::_bind_methods() {
}
VisualScriptSwitch::VisualScriptSwitch() {
}
//////////////////////////////////////////
////////////////EVENT ACTION FILTER///////////
//////////////////////////////////////////
int VisualScriptInputFilter::get_output_sequence_port_count() const {
return filters.size();
}
bool VisualScriptInputFilter::has_input_sequence_port() const{
return true;
}
int VisualScriptInputFilter::get_input_value_port_count() const{
return 1;
}
int VisualScriptInputFilter::get_output_value_port_count() const{
return 1;
}
String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const {
String text;
switch(filters[p_port].type) {
case InputEvent::NONE: {
text="None";
} break;
case InputEvent::KEY: {
InputEventKey k = filters[p_port].key;
if (k.scancode==0 && k.unicode==0) {
text="No Key";
} else {
if (k.scancode!=0) {
text="KeyCode: "+keycode_get_string(k.scancode);
} else if (k.unicode!=0) {
text="Uniode: "+String::chr(k.unicode);
}
if (k.pressed)
text+=", Pressed";
else
text+=", Released";
if (k.echo)
text+=", Echo";
if (k.mod.alt)
text="Alt+"+text;
if (k.mod.shift)
text="Shift+"+text;
if (k.mod.control)
text="Ctrl+"+text;
if (k.mod.meta)
text="Meta+"+text;
}
} break;
case InputEvent::MOUSE_MOTION: {
InputEventMouseMotion mm = filters[p_port].mouse_motion;
text="Mouse Motion";
String b = "Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight";
for(int i=0;i<7;i++) {
if (mm.button_mask&(1<<i)) {
text=b.get_slice(",",i)+"+"+text;
}
}
if (mm.mod.alt)
text="Alt+"+text;
if (mm.mod.shift)
text="Shift+"+text;
if (mm.mod.control)
text="Ctrl+"+text;
if (mm.mod.meta)
text="Meta+"+text;
} break;
case InputEvent::MOUSE_BUTTON: {
InputEventMouseButton mb = filters[p_port].mouse_button;
String b = "Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight";
text=b.get_slice(",",mb.button_index)+" Mouse Button";
if (mb.pressed)
text+=", Pressed";
else
text+=", Released";
if (mb.doubleclick)
text+=", DblClick";
if (mb.mod.alt)
text="Alt+"+text;
if (mb.mod.shift)
text="Shift+"+text;
if (mb.mod.control)
text="Ctrl+"+text;
if (mb.mod.meta)
text="Meta+"+text;
} break;
case InputEvent::JOYSTICK_MOTION: {
InputEventJoystickMotion jm = filters[p_port].joy_motion;
text="JoyMotion Axis "+itos(jm.axis>>1);
if (jm.axis&1)
text+=" > "+rtos(jm.axis_value);
else
text+=" < "+rtos(-jm.axis_value);
} break;
case InputEvent::JOYSTICK_BUTTON: {
InputEventJoystickButton jb = filters[p_port].joy_button;
text="JoyButton "+itos(jb.button_index);
if (jb.pressed)
text+=", Pressed";
else
text+=", Released";
} break;
case InputEvent::SCREEN_TOUCH: {
InputEventScreenTouch sd = filters[p_port].screen_touch;
text="Touch Finger "+itos(sd.index);
if (sd.pressed)
text+=", Pressed";
else
text+=", Released";
} break;
case InputEvent::SCREEN_DRAG: {
InputEventScreenDrag sd = filters[p_port].screen_drag;
text="Drag Finger "+itos(sd.index);
} break;
case InputEvent::ACTION: {
List<PropertyInfo> pinfo;
Globals::get_singleton()->get_property_list(&pinfo);
int index=1;
text="No Action";
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
if (!pi.name.begins_with("input/"))
continue;
if (filters[p_port].action.action==index) {
text="Action "+pi.name.substr(pi.name.find("/")+1,pi.name.length());
break;
}
index++;
}
if (filters[p_port].action.pressed)
text+=", Pressed";
else
text+=", Released";
} break;
}
return text+" - "+itos(p_port);
}
PropertyInfo VisualScriptInputFilter::get_input_value_port_info(int p_idx) const{
return PropertyInfo(Variant::INPUT_EVENT,"event");
}
PropertyInfo VisualScriptInputFilter::get_output_value_port_info(int p_idx) const{
return PropertyInfo(Variant::INPUT_EVENT,"");
}
String VisualScriptInputFilter::get_caption() const {
return "InputFilter";
}
String VisualScriptInputFilter::get_text() const {
return "";
}
bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_value) {
if (p_name=="filter_count") {
filters.resize(p_value);
_change_notify();
ports_changed_notify();
return true;
}
if (String(p_name).begins_with("filter_")) {
int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int();
ERR_FAIL_INDEX_V(idx,filters.size(),false);
String what = String(p_name).get_slice("/",1);
if (what=="type") {
filters[idx]=InputEvent();
filters[idx].type=InputEvent::Type(int(p_value));
if (filters[idx].type==InputEvent::JOYSTICK_MOTION) {
filters[idx].joy_motion.axis_value=0.5; //for treshold
} else if (filters[idx].type==InputEvent::KEY) {
filters[idx].key.pressed=true; //put these as true to make it more user friendly
} else if (filters[idx].type==InputEvent::MOUSE_BUTTON) {
filters[idx].mouse_button.pressed=true;
} else if (filters[idx].type==InputEvent::JOYSTICK_BUTTON) {
filters[idx].joy_button.pressed=true;
} else if (filters[idx].type==InputEvent::SCREEN_TOUCH) {
filters[idx].screen_touch.pressed=true;
} else if (filters[idx].type==InputEvent::ACTION) {
filters[idx].action.pressed=true;
}
_change_notify();
ports_changed_notify();
return true;
}
if (what=="device") {
filters[idx].device=p_value;
ports_changed_notify();
return true;
}
switch(filters[idx].type) {
case InputEvent::KEY: {
if (what=="scancode") {
String sc = p_value;
if (sc==String()) {
filters[idx].key.scancode=0;
} else {
filters[idx].key.scancode=find_keycode(p_value);
}
} else if (what=="unicode") {
String uc = p_value;
if (uc==String()) {
filters[idx].key.unicode=0;
} else {
filters[idx].key.unicode=uc[0];
}
} else if (what=="pressed") {
filters[idx].key.pressed=p_value;
} else if (what=="echo") {
filters[idx].key.echo=p_value;
} else if (what=="mod_alt") {
filters[idx].key.mod.alt=p_value;
} else if (what=="mod_shift") {
filters[idx].key.mod.shift=p_value;
} else if (what=="mod_ctrl") {
filters[idx].key.mod.control=p_value;
} else if (what=="mod_meta") {
filters[idx].key.mod.meta=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::MOUSE_MOTION: {
if (what=="button_mask") {
filters[idx].mouse_motion.button_mask=p_value;
} else if (what=="mod_alt") {
filters[idx].mouse_motion.mod.alt=p_value;
} else if (what=="mod_shift") {
filters[idx].mouse_motion.mod.shift=p_value;
} else if (what=="mod_ctrl") {
filters[idx].mouse_motion.mod.control=p_value;
} else if (what=="mod_meta") {
filters[idx].mouse_motion.mod.meta=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::MOUSE_BUTTON: {
if (what=="button_index") {
filters[idx].mouse_button.button_index=p_value;
} else if (what=="pressed") {
filters[idx].mouse_button.pressed=p_value;
} else if (what=="doubleclicked") {
filters[idx].mouse_button.doubleclick=p_value;
} else if (what=="mod_alt") {
filters[idx].mouse_button.mod.alt=p_value;
} else if (what=="mod_shift") {
filters[idx].mouse_button.mod.shift=p_value;
} else if (what=="mod_ctrl") {
filters[idx].mouse_button.mod.control=p_value;
} else if (what=="mod_meta") {
filters[idx].mouse_button.mod.meta=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::JOYSTICK_MOTION: {
if (what=="axis") {
filters[idx].joy_motion.axis=int(p_value)<<1|filters[idx].joy_motion.axis;
} else if (what=="mode") {
filters[idx].joy_motion.axis|=int(p_value);
} else if (what=="treshold") {
filters[idx].joy_motion.axis_value=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::JOYSTICK_BUTTON: {
if (what=="button_index") {
filters[idx].joy_button.button_index=p_value;
} else if (what=="pressed") {
filters[idx].joy_button.pressed=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::SCREEN_TOUCH: {
if (what=="finger_index") {
filters[idx].screen_touch.index=p_value;
} else if (what=="pressed") {
filters[idx].screen_touch.pressed=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::SCREEN_DRAG: {
if (what=="finger_index") {
filters[idx].screen_drag.index=p_value;
} else {
return false;
}
ports_changed_notify();
return true;
} break;
case InputEvent::ACTION: {
if (what=="action_name") {
List<PropertyInfo> pinfo;
Globals::get_singleton()->get_property_list(&pinfo);
int index=1;
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
if (!pi.name.begins_with("input/"))
continue;
String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
if (name==String(p_value)) {
filters[idx].action.action=index;
ports_changed_notify();
return true;
}
index++;
}
filters[idx].action.action=0;
ports_changed_notify();
return false;
} else if (what=="pressed") {
filters[idx].action.pressed=p_value;
ports_changed_notify();
return true;
}
} break;
}
}
return false;
}
bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) const{
if (p_name=="filter_count") {
r_ret=filters.size();
return true;
}
if (String(p_name).begins_with("filter_")) {
int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int();
ERR_FAIL_INDEX_V(idx,filters.size(),false);
String what = String(p_name).get_slice("/",1);
if (what=="type") {
r_ret=filters[idx].type;
return true;
}
if (what=="device") {
r_ret=filters[idx].device;
return true;
}
switch(filters[idx].type) {
case InputEvent::KEY: {
if (what=="scancode") {
if (filters[idx].key.scancode==0)
r_ret=String();
else {
r_ret=keycode_get_string(filters[idx].key.scancode);
}
} else if (what=="unicode") {
if (filters[idx].key.unicode==0) {
r_ret=String();
} else {
CharType str[2]={ (CharType)filters[idx].key.unicode, 0};
r_ret=String(str);
}
} else if (what=="pressed") {
r_ret=filters[idx].key.pressed;
} else if (what=="echo") {
r_ret=filters[idx].key.echo;
} else if (what=="mod_alt") {
r_ret=filters[idx].key.mod.alt;
} else if (what=="mod_shift") {
r_ret=filters[idx].key.mod.shift;
} else if (what=="mod_ctrl") {
r_ret=filters[idx].key.mod.control;
} else if (what=="mod_meta") {
r_ret=filters[idx].key.mod.meta;
} else {
return false;
}
return true;
} break;
case InputEvent::MOUSE_MOTION: {
if (what=="button_mask") {
r_ret=filters[idx].mouse_motion.button_mask;
} else if (what=="mod_alt") {
r_ret=filters[idx].mouse_motion.mod.alt;
} else if (what=="mod_shift") {
r_ret=filters[idx].mouse_motion.mod.shift;
} else if (what=="mod_ctrl") {
r_ret=filters[idx].mouse_motion.mod.control;
} else if (what=="mod_meta") {
r_ret=filters[idx].mouse_motion.mod.meta;
} else {
return false;
}
return true;
} break;
case InputEvent::MOUSE_BUTTON: {
if (what=="button_index") {
r_ret=filters[idx].mouse_button.button_index;
} else if (what=="pressed") {
r_ret=filters[idx].mouse_button.pressed;
} else if (what=="doubleclicked") {
r_ret=filters[idx].mouse_button.doubleclick;
} else if (what=="mod_alt") {
r_ret=filters[idx].mouse_button.mod.alt;
} else if (what=="mod_shift") {
r_ret=filters[idx].mouse_button.mod.shift;
} else if (what=="mod_ctrl") {
r_ret=filters[idx].mouse_button.mod.control;
} else if (what=="mod_meta") {
r_ret=filters[idx].mouse_button.mod.meta;
} else {
return false;
}
return true;
} break;
case InputEvent::JOYSTICK_MOTION: {
if (what=="axis_index") {
r_ret=filters[idx].joy_motion.axis>>1;
} else if (what=="mode") {
r_ret=filters[idx].joy_motion.axis&1;
} else if (what=="treshold") {
r_ret=filters[idx].joy_motion.axis_value;
} else {
return false;
}
return true;
} break;
case InputEvent::JOYSTICK_BUTTON: {
if (what=="button_index") {
r_ret=filters[idx].joy_button.button_index;
} else if (what=="pressed") {
r_ret=filters[idx].joy_button.pressed;
} else {
return false;
}
return true;
} break;
case InputEvent::SCREEN_TOUCH: {
if (what=="finger_index") {
r_ret=filters[idx].screen_touch.index;
} else if (what=="pressed") {
r_ret=filters[idx].screen_touch.pressed;
} else {
return false;
}
return true;
} break;
case InputEvent::SCREEN_DRAG: {
if (what=="finger_index") {
r_ret=filters[idx].screen_drag.index;
} else {
return false;
}
return true;
} break;
case InputEvent::ACTION: {
if (what=="action_name") {
List<PropertyInfo> pinfo;
Globals::get_singleton()->get_property_list(&pinfo);
int index=1;
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
if (!pi.name.begins_with("input/"))
continue;
if (filters[idx].action.action==index) {
r_ret=pi.name.substr(pi.name.find("/")+1,pi.name.length());
return true;
}
index++;
}
r_ret="None"; //no index
return false;
} else if (what=="pressed") {
r_ret=filters[idx].action.pressed;
return true;
}
} break;
}
}
return false;
}
static const char* event_type_names[InputEvent::TYPE_MAX]={
"None",
"Key",
"MouseMotion",
"MouseButton",
"JoystickMotion",
"JoystickButton",
"ScreenTouch",
"ScreenDrag",
"Action"
};
void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64"));
String et;
for(int i=0;i<InputEvent::TYPE_MAX;i++) {
if (i>0)
et+=",";
et+=event_type_names[i];
}
String kc;
String actions;
for(int i=0;i<filters.size();i++) {
String base = "filter_"+itos(i)+"/";
p_list->push_back(PropertyInfo(Variant::INT,base+"type",PROPERTY_HINT_ENUM,et));
p_list->push_back(PropertyInfo(Variant::INT,base+"device"));
switch(filters[i].type) {
case InputEvent::NONE: {
} break;
case InputEvent::KEY: {
if (kc==String()) {
int kcc = keycode_get_count();
kc="None";
for(int i=0;i<kcc;i++) {
kc+=",";
kc+=String(keycode_get_name_by_index(i));
}
}
p_list->push_back(PropertyInfo(Variant::STRING,base+"scancode",PROPERTY_HINT_ENUM,kc));
p_list->push_back(PropertyInfo(Variant::STRING,base+"unicode"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"echo"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
} break;
case InputEvent::MOUSE_MOTION: {
p_list->push_back(PropertyInfo(Variant::INT,base+"button_mask",PROPERTY_HINT_FLAGS,"Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
} break;
case InputEvent::MOUSE_BUTTON: {
p_list->push_back(PropertyInfo(Variant::INT,base+"button_index",PROPERTY_HINT_ENUM,"Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"doubleclicked"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
} break;
case InputEvent::JOYSTICK_MOTION: {
p_list->push_back(PropertyInfo(Variant::INT,base+"axis_index"));
p_list->push_back(PropertyInfo(Variant::INT,base+"mode",PROPERTY_HINT_ENUM,"Min,Max"));
p_list->push_back(PropertyInfo(Variant::REAL,base+"treshold",PROPERTY_HINT_RANGE,"0,1,0.01"));
} break;
case InputEvent::JOYSTICK_BUTTON: {
p_list->push_back(PropertyInfo(Variant::INT,base+"button_index"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
} break;
case InputEvent::SCREEN_TOUCH: {
p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index"));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
} break;
case InputEvent::SCREEN_DRAG: {
p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index"));
} break;
case InputEvent::ACTION: {
if (actions==String()) {
actions="None";
List<PropertyInfo> pinfo;
Globals::get_singleton()->get_property_list(&pinfo);
Vector<String> al;
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
if (!pi.name.begins_with("input/"))
continue;
String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
al.push_back(name);
}
for(int i=0;i<al.size();i++) {
actions+=",";
actions+=al[i];
}
}
p_list->push_back(PropertyInfo(Variant::STRING,base+"action_name",PROPERTY_HINT_ENUM,actions));
p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
} break;
}
}
}
class VisualScriptNodeInstanceInputFilter : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
Vector<InputEvent> filters;
//virtual int get_working_memory_size() const { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) {
r_error_str="Input value not of type event";
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
return 0;
}
InputEvent event = *p_inputs[0];
for(int i=0;i<filters.size();i++) {
const InputEvent &ie = filters[i];
if (ie.type!=event.type)
continue;
bool match=false;
switch(ie.type) {
case InputEvent::NONE: {
match=true;
} break;
case InputEvent::KEY: {
InputEventKey k = ie.key;
InputEventKey k2 = event.key;
if (k.scancode==0 && k.unicode==0 && k2.scancode==0 && k2.unicode==0) {
match=true;
} else {
if ( (k.scancode!=0 && k.scancode==k2.scancode) || (k.unicode!=0 && k.unicode==k2.unicode)) {
//key valid
if (
k.pressed==k2.pressed &&
k.echo==k2.echo &&
k.mod == k2.mod
) {
match=true;
}
}
}
} break;
case InputEvent::MOUSE_MOTION: {
InputEventMouseMotion mm = ie.mouse_motion;
InputEventMouseMotion mm2 = event.mouse_motion;
if ( mm.button_mask==mm2.button_mask &&
mm.mod==mm2.mod
) {
match=true;
}
} break;
case InputEvent::MOUSE_BUTTON: {
InputEventMouseButton mb = ie.mouse_button;
InputEventMouseButton mb2 = event.mouse_button;
if ( mb.button_index==mb2.button_index &&
mb.pressed==mb2.pressed &&
mb.doubleclick==mb2.doubleclick &&
mb.mod==mb2.mod) {
match=true;
}
} break;
case InputEvent::JOYSTICK_MOTION: {
InputEventJoystickMotion jm = ie.joy_motion;
InputEventJoystickMotion jm2 = event.joy_motion;
int axis = jm.axis>>1;
if (axis==jm2.axis) {
if (jm.axis&1) {
//greater
if (jm2.axis_value > jm.axis_value) {
match=true;
}
} else {
//less
if (jm2.axis_value < -jm.axis_value) {
match=true;
}
}
}
} break;
case InputEvent::JOYSTICK_BUTTON: {
InputEventJoystickButton jb = ie.joy_button;
InputEventJoystickButton jb2 = event.joy_button;
if ( jb.button_index==jb2.button_index &&
jb.pressed == jb2.pressed
) {
match=true;
}
} break;
case InputEvent::SCREEN_TOUCH: {
InputEventScreenTouch st = ie.screen_touch;
InputEventScreenTouch st2 = event.screen_touch;
if ( st.index==st2.index &&
st.pressed==st2.pressed) {
match=true;
}
} break;
case InputEvent::SCREEN_DRAG: {
InputEventScreenDrag sd = ie.screen_drag;
InputEventScreenDrag sd2 = event.screen_drag;
if (sd.index==sd2.index) {
match=true;
}
} break;
case InputEvent::ACTION: {
InputEventAction ia = ie.action;
InputEventAction ia2 = event.action;
if ( ia.action==ia2.action &&
ia.pressed==ia2.pressed) {
match=true;
}
} break;
}
*p_outputs[0] = event;
if (match)
return i; //go through match output
}
return STEP_NO_ADVANCE_BIT; //none found, don't advance
}
};
VisualScriptNodeInstance* VisualScriptInputFilter::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceInputFilter * instance = memnew(VisualScriptNodeInstanceInputFilter );
instance->instance=p_instance;
instance->filters=filters;
return instance;
}
VisualScriptInputFilter::VisualScriptInputFilter() {
}
//////////////////////////////////////////
////////////////TYPE CAST///////////
//////////////////////////////////////////
int VisualScriptTypeCast::get_output_sequence_port_count() const {
return 2;
}
bool VisualScriptTypeCast::has_input_sequence_port() const{
return true;
}
int VisualScriptTypeCast::get_input_value_port_count() const{
return 1;
}
int VisualScriptTypeCast::get_output_value_port_count() const{
return 1;
}
String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const {
return p_port==0 ? "yes" : "no";
}
PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const{
return PropertyInfo(Variant::OBJECT,"instance");
}
PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const{
return PropertyInfo(Variant::OBJECT,"");
}
String VisualScriptTypeCast::get_caption() const {
return "TypeCast";
}
String VisualScriptTypeCast::get_text() const {
if (script!=String())
return "Is "+script.get_file()+"?";
else
return "Is "+base_type+"?";
}
void VisualScriptTypeCast::set_base_type(const StringName& p_type) {
if (base_type==p_type)
return;
base_type=p_type;
_change_notify();
ports_changed_notify();
}
StringName VisualScriptTypeCast::get_base_type() const{
return base_type;
}
void VisualScriptTypeCast::set_base_script(const String& p_path){
if (script==p_path)
return;
script=p_path;
_change_notify();
ports_changed_notify();
}
String VisualScriptTypeCast::get_base_script() const{
return script;
}
class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
StringName base_type;
String script;
//virtual int get_working_memory_size() const { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
Object *obj = *p_inputs[0];
*p_outputs[0]=Variant();
if (!obj) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str="Instance is null";
return 0;
}
if (script!=String()) {
Ref<Script> obj_script = obj->get_script();
if (!obj_script.is_valid()) {
return 1; //well, definitely not the script because object we got has no script.
}
if (!ResourceCache::has(script)) {
//if the script is not in use by anyone, we can safely assume whathever we got is not casting to it.
return 1;
}
Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
if (!cast_script.is_valid()) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str="Script path is not a script: "+script;
return 1;
}
while(obj_script.is_valid()) {
if (cast_script==obj_script) {
*p_outputs[0]=*p_inputs[0]; //copy
return 0; // it is the script, yey
}
obj_script=obj_script->get_base_script();
}
return 1; //not found sorry
}
if (ClassDB::is_parent_class(obj->get_class_name(),base_type)) {
*p_outputs[0]=*p_inputs[0]; //copy
return 0;
} else
return 1;
}
};
VisualScriptNodeInstance* VisualScriptTypeCast::instance(VisualScriptInstance* p_instance) {
VisualScriptNodeInstanceTypeCast * instance = memnew(VisualScriptNodeInstanceTypeCast );
instance->instance=p_instance;
instance->base_type=base_type;
instance->script=script;
return instance;
}
void VisualScriptTypeCast::_bind_methods() {
ClassDB::bind_method(_MD("set_base_type","type"),&VisualScriptTypeCast::set_base_type);
ClassDB::bind_method(_MD("get_base_type"),&VisualScriptTypeCast::get_base_type);
ClassDB::bind_method(_MD("set_base_script","path"),&VisualScriptTypeCast::set_base_script);
ClassDB::bind_method(_MD("get_base_script"),&VisualScriptTypeCast::get_base_script);
List<String> script_extensions;
for(int i=0;i>ScriptServer::get_language_count();i++) {
ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
}
String script_ext_hint;
for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
if (script_ext_hint!=String())
script_ext_hint+=",";
script_ext_hint+="*."+E->get();
}
ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
}
VisualScriptTypeCast::VisualScriptTypeCast() {
base_type="Object";
}
void register_visual_script_flow_control_nodes() {
VisualScriptLanguage::singleton->add_register_func("flow_control/return",create_return_node<false>);
VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value",create_return_node<true>);
VisualScriptLanguage::singleton->add_register_func("flow_control/condition",create_node_generic<VisualScriptCondition>);
VisualScriptLanguage::singleton->add_register_func("flow_control/while",create_node_generic<VisualScriptWhile>);
VisualScriptLanguage::singleton->add_register_func("flow_control/iterator",create_node_generic<VisualScriptIterator>);
VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>);
VisualScriptLanguage::singleton->add_register_func("flow_control/switch",create_node_generic<VisualScriptSwitch>);
VisualScriptLanguage::singleton->add_register_func("flow_control/input_filter",create_node_generic<VisualScriptInputFilter>);
VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast",create_node_generic<VisualScriptTypeCast>);
}