void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */ { m_refcount = 1; #ifdef _DEBUG //gRefCountValue++; #endif PyObjectPlus::ProcessReplica(); m_ValFlags.RefCountDisabled = false; /* copy all props */ if (m_pNamedPropertyArray) { std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray; m_pNamedPropertyArray=NULL; std::map<STR_String,CValue*>::iterator it; for (it= pOldArray->begin(); (it != pOldArray->end()); it++) { CValue *val = (*it).second->GetReplica(); SetProperty((*it).first,val); val->Release(); } } }
CValue* CIfExpr::Calculate() /* pre: ret: a new object containing the value of m_e1 if m_guard is a boolean TRUE a new object containing the value of m_e2 if m_guard is a boolean FALSE an new errorvalue if m_guard is not a boolean */ { CValue *guardval; guardval = m_guard->Calculate(); const STR_String& text = guardval->GetText(); guardval->Release(); if (&text == &CBoolValue::sTrueString) { return m_e1->Calculate(); } else if (&text == &CBoolValue::sFalseString) { return m_e2->Calculate(); } else { return new CErrorValue("Guard should be of boolean type"); } }
void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr) { bool expressionresult = false; if (!m_exprCache) { CParser parser; parser.SetContext(this->AddRef()); m_exprCache = parser.ProcessText(m_exprText); } if (m_exprCache) { CValue* value = m_exprCache->Calculate(); if (value) { if (value->IsError()) { printf("%s\n", value->GetText().ReadPtr()); } else { float num = (float)value->GetNumber(); expressionresult = !MT_fuzzyZero(num); } value->Release(); } } for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { SCA_IActuator* actua = *i; logicmgr->AddActiveActuator(actua,expressionresult); } }
PyObject *CListValue::Pyindex(PyObject *value) { PyObject *result = NULL; CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, "); if (checkobj==NULL) return NULL; /* ConvertPythonToValue sets the error */ int numelem = GetCount(); for (int i=0;i<numelem;i++) { CValue* elem = GetValue(i); if (checkobj==elem || CheckEqual(checkobj,elem)) { result = PyLong_FromLong(i); break; } } checkobj->Release(); if (result==NULL) { PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue"); } return result; }
SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, SCA_IObject* gameobj, const STR_String& propname, const STR_String& propval, const STR_String& propmaxval, KX_PROPSENSOR_TYPE checktype) : SCA_ISensor(gameobj,eventmgr), m_checktype(checktype), m_checkpropval(propval), m_checkpropmaxval(propmaxval), m_checkpropname(propname), m_range_expr(NULL) { //CParser pars; //pars.SetContext(this->AddRef()); //CValue* resultval = m_rightexpr->Calculate(); CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { m_previoustext = orgprop->GetText(); } orgprop->Release(); if (m_checktype==KX_PROPSENSOR_INTERVAL) { PrecalculateRangeExpression(); } Init(); }
CValue * COperator1Expr::Calculate() /* pre: ret: a new object containing the result of applying the operator m_op to the value of m_lhs */ { CValue *ret; CValue *temp = m_lhs->Calculate(); CValue* empty = new CEmptyValue(); ret = empty->Calc(m_op, temp); empty->Release(); temp->Release(); return ret; }
CValue* SCA_ILogicBrick::Calc(VALUE_OPERATOR op, CValue *val) { CValue* temp = new CBoolValue(false,""); CValue* result = temp->Calc(op,val); temp->Release(); return result; }
CValue* COperator2Expr::Calculate() /* pre: ret: a new object containing the result of applying operator m_op to m_lhs and m_rhs */ { bool leftmodified,rightmodified; leftmodified = m_lhs->NeedsRecalculated(); rightmodified = m_rhs->NeedsRecalculated(); // if no modifications on both left and right subtree, and result is already calculated // then just return cached result... if (!leftmodified && !rightmodified && (m_cached_calculate)) { // not modified, just return m_cached_calculate } else { // if not yet calculated, or modified... if (m_cached_calculate) { m_cached_calculate->Release(); m_cached_calculate=NULL; } CValue* ffleft = m_lhs->Calculate(); CValue* ffright = m_rhs->Calculate(); ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this; ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this; m_cached_calculate = ffleft->Calc(m_op,ffright); //if (m_cached_calculate) // m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE)); ffleft->Release(); ffright->Release(); } return m_cached_calculate->AddRef(); }
CValue* SCA_ILogicBrick::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) { // same as bool implementation, so... CValue* temp = new CBoolValue(false,""); CValue* result = temp->CalcFinal(dtype,op,val); temp->Release(); return result; }
bool CListValue::CheckEqual(CValue* first,CValue* second) { bool result = false; CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second); if (eqval==NULL) return false; const STR_String& text = eqval->GetText(); if (&text==&CBoolValue::sTrueString) { result = true; } eqval->Release(); return result; }
int SCA_ILogicBrick::CheckProperty(void *self, const PyAttributeDef *attrdef) { if (attrdef->m_type != KX_PYATTRIBUTE_TYPE_STRING || attrdef->m_length != 1) { PyErr_SetString(PyExc_AttributeError, "inconsistent check function for attribute type, report to blender.org"); return 1; } SCA_ILogicBrick* brick = reinterpret_cast<SCA_ILogicBrick*>(self); STR_String* var = reinterpret_cast<STR_String*>((char*)self+attrdef->m_offset); CValue* prop = brick->GetParent()->FindIdentifier(*var); bool error = prop->IsError(); prop->Release(); if (error) { PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); return 1; } return 0; }
// // Clear all properties // void CValue::ClearProperties() { // Check if we have any properties if (m_pNamedPropertyArray == NULL) return; // Remove all properties std::map<STR_String,CValue*>::iterator it; for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) { CValue* tmpval = (*it).second; //STR_String name = (*it).first; tmpval->Release(); } // Delete property array delete m_pNamedPropertyArray; m_pNamedPropertyArray=NULL; }
int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_FontObject* self = static_cast<KX_FontObject*>(self_v); if (!PyUnicode_Check(value)) return PY_SET_ATTR_FAIL; char* chars = _PyUnicode_AsString(value); /* Allow for some logic brick control */ CValue* tprop = self->GetProperty("Text"); if (tprop) { CValue *newstringprop = new CStringValue(STR_String(chars), "Text"); self->SetProperty("Text", newstringprop); newstringprop->Release(); } else { self->m_text = split_string(STR_String(chars)); } return PY_SET_ATTR_SUCCESS; }
/** * pre: * ret: a new object containing the value of m_e1 if m_guard is a boolean true * a new object containing the value of m_e2 if m_guard is a boolean false * an new errorvalue if m_guard is not a boolean */ CValue* CIfExpr::Calculate() { CValue *guardval; guardval = m_guard->Calculate(); const std::string& text = guardval->GetText(); guardval->Release(); if (text == CBoolValue::sTrueString) { return m_e1->Calculate(); } else if (text == CBoolValue::sFalseString) { return m_e2->Calculate(); } else { return new CErrorValue("Guard should be of boolean type"); } }
void CValue::SetProperty(const char* name,CValue* ioProperty) { if (ioProperty==NULL) { // Check if somebody is setting an empty property trace("Warning:trying to set empty property!"); return; } if (m_pNamedPropertyArray) { // Try to replace property (if so -> exit as soon as we replaced it) CValue* oldval = (*m_pNamedPropertyArray)[name]; if (oldval) oldval->Release(); } else { // Make sure we have a property array m_pNamedPropertyArray = new std::map<STR_String,CValue *>; } // Add property at end of array (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); }
PyObject *CListValue::Pycount(PyObject *value) { int numfound = 0; CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */ if (checkobj==NULL) { /* in this case just return that there are no items in the list */ PyErr_Clear(); return PyLong_FromLong(0); } int numelem = GetCount(); for (int i=0;i<numelem;i++) { CValue* elem = GetValue(i); if (checkobj==elem || CheckEqual(checkobj,elem)) { numfound ++; } } checkobj->Release(); return PyLong_FromLong(numfound); }
bool BL_ActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool bUseContinue = false; KX_GameObject *obj = (KX_GameObject*)GetParent(); short playtype = BL_Action::ACT_MODE_PLAY; float start = m_startframe; float end = m_endframe; // If we don't have an action, we can't do anything if (!m_action) return false; // Convert our playtype to one that BL_Action likes switch(m_playtype) { case ACT_ACTION_LOOP_END: case ACT_ACTION_LOOP_STOP: playtype = BL_Action::ACT_MODE_LOOP; break; case ACT_ACTION_PINGPONG: // We handle ping pong ourselves to increase compabitility // with files made prior to animation changes from GSoC 2011. playtype = BL_Action::ACT_MODE_PLAY; if (m_flag & ACT_FLAG_REVERSE) { start = m_endframe; end = m_startframe; } break; case ACT_ACTION_FROM_PROP: CValue* prop = GetParent()->GetProperty(m_propname); // If we don't have a property, we can't do anything, so just bail if (!prop) return false; playtype = BL_Action::ACT_MODE_PLAY; start = end = prop->GetNumber(); break; } if (m_flag & ACT_FLAG_CONTINUE) bUseContinue = true; // Handle events if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); } // "Active" actions need to keep updating their current frame if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE)) m_localtime = obj->GetActionFrame(m_layer); if (m_flag & ACT_FLAG_ATTEMPT_PLAY) SetLocalTime(curtime); else ResetStartTime(curtime); // Handle a frame property if it's defined if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0) { CValue* oldprop = obj->GetProperty(m_framepropname); CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer)); if (oldprop) oldprop->SetValue(newval); else obj->SetProperty(m_framepropname, newval); newval->Release(); } // Handle a finished animation if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; if (m_playtype == ACT_ACTION_PINGPONG) m_flag ^= ACT_FLAG_REVERSE; return false; } // If a different action is playing, we've been overruled and are no longer active if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer)) m_flag &= ~ACT_FLAG_ACTIVE; if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE))) { if (bPositiveEvent && m_playtype == ACT_ACTION_PLAY) { if (obj->IsActionDone(m_layer)) m_localtime = start; ResetStartTime(curtime); } if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) { m_flag |= ACT_FLAG_ACTIVE; if (bUseContinue) obj->SetActionFrame(m_layer, m_localtime); if (m_playtype == ACT_ACTION_PLAY || m_playtype == ACT_ACTION_PINGPONG) m_flag |= ACT_FLAG_PLAY_END; else m_flag &= ~ACT_FLAG_PLAY_END; } m_flag |= ACT_FLAG_ATTEMPT_PLAY; } else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent) { m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; m_localtime = obj->GetActionFrame(m_layer); bAction *curr_action = obj->GetCurrentAction(m_layer); if (curr_action && curr_action != m_action) { // Someone changed the action on us, so we wont mess with it // Hopefully there wont be too many problems with two actuators using // the same action... m_flag &= ~ACT_FLAG_ACTIVE; return false; } switch(m_playtype) { case ACT_ACTION_LOOP_STOP: obj->StopAction(m_layer); // Stop the action after getting the frame // We're done m_flag &= ~ACT_FLAG_ACTIVE; return false; case ACT_ACTION_LOOP_END: // Convert into a play and let it finish obj->SetPlayMode(m_layer, BL_Action::ACT_MODE_PLAY); m_flag |= ACT_FLAG_PLAY_END; break; case ACT_ACTION_FLIPPER: // Convert into a play action and play back to the beginning end = start; start = obj->GetActionFrame(m_layer); obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags); m_flag |= ACT_FLAG_PLAY_END; break; } } return m_flag & ACT_FLAG_ACTIVE; }
CExpression *CParser::Ex(int i) { // parses an expression in the input, starting at priority i, and // returns an CExpression, containing the parsed input CExpression *e1 = NULL, *e2 = NULL; int opkind2; if (i < NUM_PRIORITY) { e1 = Ex(i + 1); while ((sym == opsym) && (Priority(opkind) == i)) { opkind2 = opkind; NextSym(); e2 = Ex(i + 1); switch (opkind2) { case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break; case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break; case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break; case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break; case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break; case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break; case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break; case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break; case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break; case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break; case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break; case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break; case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break; default: MT_assert(false); break; // should not happen } } } else if (i == NUM_PRIORITY) { if ((sym == opsym) && ( (opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus) ) ) { NextSym(); switch (opkind) { /* +1 is also a valid number! */ case OPplus: e1 = new COperator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY)); break; case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break; case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break; default: { // should not happen e1 = Error("operator +, - or ! expected"); } } } else { switch (sym) { case constsym: { switch (constkind) { case booltype: e1 = new CConstExpr(new CBoolValue(boolvalue)); break; case inttype: { cInt temp; temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */ e1 = new CConstExpr(new CIntValue(temp)); break; } case floattype: { double temp; temp = atof(const_as_string); e1 = new CConstExpr(new CFloatValue(temp)); break; } case stringtype: e1 = new CConstExpr(new CStringValue(const_as_string,"")); break; default : MT_assert(false); break; } NextSym(); break; } case lbracksym: NextSym(); e1 = Ex(1); Term(rbracksym); break; case ifsym: { CExpression *e3; NextSym(); Term(lbracksym); e1 = Ex(1); Term(commasym); e2 = Ex(1); if (sym == commasym) { NextSym(); e3 = Ex(1); } else { e3 = new CConstExpr(new CEmptyValue()); } Term(rbracksym); e1 = new CIfExpr(e1, e2, e3); break; } case idsym: { e1 = new CIdentifierExpr(const_as_string,m_identifierContext); NextSym(); break; } case errorsym: { MT_assert(!e1); STR_String errtext="[no info]"; if (errmsg) { CValue* errmsgval = errmsg->Calculate(); errtext=errmsgval->GetText(); errmsgval->Release(); //e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate()); if ( !(errmsg->Release()) ) { errmsg=NULL; } else { // does this happen ? MT_assert("does this happen"); } } e1 = Error(errtext); break; } default: NextSym(); //return Error("Expression expected"); MT_assert(!e1); e1 = Error("Expression expected"); } } } return e1; }
bool BL_ActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool keepgoing = true; bool wrap = false; bool apply=true; int priority; float newweight; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; if (bNegativeEvent) { // dont continue where we left off when restarting if (m_end_reset) { m_flag &= ~ACT_FLAG_LOCKINPUT; } if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; } } /* We know that action actuators have been discarded from all non armature objects: if we're being called, we're attached to a BL_ArmatureObject */ BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); float length = m_endframe - m_startframe; priority = m_priority; /* Determine pre-incrementation behaviour and set appropriate flags */ switch (m_playtype){ case ACT_ACTION_MOTION: if (bNegativeEvent){ keepgoing=false; apply=false; }; break; case ACT_ACTION_FROM_PROP: if (bNegativeEvent){ apply=false; keepgoing=false; } break; case ACT_ACTION_LOOP_END: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; m_localtime = m_startframe; m_starttime = curtime; } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; } break; case ACT_ACTION_LOOP_STOP: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_KEYUP; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_LOCKINPUT; keepgoing=false; apply=false; } break; case ACT_ACTION_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0; /* Apply the pose if necessary*/ if (apply){ /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ /* Get the underlying pose from the armature */ obj->GetPose(&m_pose); // 2.4x function, /* Override the necessary channels with ones from the action */ // XXX extract_pose_from_action(m_pose, m_action, m_localtime); // 2.5x - replacement for extract_pose_from_action(...) above. { struct PointerRNA id_ptr; Object *arm= obj->GetArmatureObject(); bPose *pose_back= arm->pose; arm->pose= m_pose; RNA_id_pointer_create((ID *)arm, &id_ptr); animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime); arm->pose= pose_back; // 2.5x - could also do this but looks too high level, constraints use this, it works ok. // Object workob; /* evaluate using workob */ // what_does_obaction((Scene *)obj->GetScene(), obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime); } // done getting the pose from the action /* Perform the user override (if any) */ if (m_userpose){ extract_pose_from_pose(m_pose, m_userpose); game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too. m_userpose = NULL; } #if 1 /* Handle blending */ if (m_blendin && (m_blendframe<m_blendin)){ /* If this is the start of a blending sequence... */ if ((m_blendframe==0.0) || (!m_blendpose)){ obj->GetMRDPose(&m_blendpose); m_blendstart = curtime; } /* Find percentages */ newweight = (m_blendframe/(float)m_blendin); game_blend_poses(m_pose, m_blendpose, 1.0 - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; } #endif m_lastUpdate = m_localtime; obj->SetPose (m_pose); } else{ m_blendframe = 0.0; } } if (!keepgoing){ m_blendframe = 0.0; } return keepgoing; };
void BL_ConvertTextProperty(Object* object, KX_FontObject* fontobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer) { CValue* tprop = fontobj->GetProperty("Text"); if(!tprop) return; bProperty* prop = get_ob_property(object, "Text"); if(!prop) return; Curve *curve = static_cast<Curve *>(object->data); STR_String str = curve->str; CValue* propval = NULL; switch(prop->type) { case GPROP_BOOL: { int value = atoi(str); propval = new CBoolValue((bool)(value != 0)); tprop->SetValue(propval); break; } case GPROP_INT: { int value = atoi(str); propval = new CIntValue(value); tprop->SetValue(propval); break; } case GPROP_FLOAT: { float floatprop = atof(str); propval = new CFloatValue(floatprop); tprop->SetValue(propval); break; } case GPROP_STRING: { propval = new CStringValue(str, ""); tprop->SetValue(propval); break; } case GPROP_TIME: { float floatprop = atof(str); CValue* timeval = new CFloatValue(floatprop); // set a subproperty called 'timer' so that // we can register the replica of this property // at the time a game object is replicated (AddObjectActuator triggers this) CValue *bval = new CBoolValue(true); timeval->SetProperty("timer",bval); bval->Release(); if (isInActiveLayer) { timemgr->AddTimeProperty(timeval); } propval = timeval; tprop->SetValue(timeval); } default: { // todo make an assert etc. } } if (propval) { propval->Release(); } }
bool KX_IpoActuator::Update(double curtime, bool frame) { // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! bool bNegativeEvent = false; bool numevents = false; bool bIpoStart = false; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); if (frame) { numevents = m_posevent || m_negevent; bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); } float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f); bool result=true; if (!bNegativeEvent) { if (m_starttime < -2.0f*fabs(m_endframe - m_startframe)) { // start for all Ipo, initial start for LOOP_STOP m_starttime = curtime; m_bIpoPlaying = true; bIpoStart = true; } } switch ((IpoActType)m_type) { case KX_ACT_IPO_PLAY: { // Check if playing forwards. result = ! finished if (start_smaller_then_end > 0.f) result = (m_localtime < m_endframe && m_bIpoPlaying); else result = (m_localtime > m_endframe && m_bIpoPlaying); if (result) { SetLocalTime(curtime); /* Perform clamping */ ClampLocalTime(); if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { m_localtime=m_startframe; m_direction=1; } break; } case KX_ACT_IPO_PINGPONG: { result = true; if (bNegativeEvent && !m_bIpoPlaying) result = false; else SetLocalTime(curtime); if (ClampLocalTime()) { result = false; m_direction = -m_direction; } if (bIpoStart && m_direction > 0) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_FLIPPER: { if (bNegativeEvent && !m_bIpoPlaying) result = false; if (numevents) { float oldDirection = m_direction; if (bNegativeEvent) m_direction = -1; else m_direction = 1; if (m_direction != oldDirection) // changing direction, reset start time SetStartTime(curtime); } SetLocalTime(curtime); if (ClampLocalTime() && m_localtime == m_startframe) result = false; if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_LOOPSTOP: { if (numevents) { if (bNegativeEvent) { result = false; m_bNegativeEvent = false; numevents = false; } if (!m_bIpoPlaying) { // Ipo was stopped, make sure we will restart from where it stopped SetStartTime(curtime); if (!bNegativeEvent) // positive signal will restart the Ipo m_bIpoPlaying = true; } } // fall through to loopend, and quit the ipo animation immediatly } case KX_ACT_IPO_LOOPEND: { if (numevents) { if (bNegativeEvent && m_bIpoPlaying) { m_bNegativeEvent = true; } } if (bNegativeEvent && !m_bIpoPlaying) { result = false; } else { if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end) { SetLocalTime(curtime); } else { if (!m_bNegativeEvent) { /* Perform wraparound */ SetLocalTime(curtime); if (start_smaller_then_end > 0.f) m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe); else m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe); SetStartTime(curtime); bIpoStart = true; } else { /* Perform clamping */ m_localtime=m_endframe; result = false; m_bNegativeEvent = false; } } } if (m_bIpoPlaying && bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_KEY2KEY: { // not implemented yet result = false; break; } case KX_ACT_IPO_FROM_PROP: { result = !bNegativeEvent; CValue* propval = GetParent()->GetProperty(m_propname); if (propval) { m_localtime = propval->GetNumber(); if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { result = false; } break; } default: result = false; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (!result) { if (m_type != KX_ACT_IPO_LOOPSTOP) this->ResetStartTime(); m_bIpoPlaying = false; } return result; }
void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer) { bProperty* prop = (bProperty*)object->prop.first; CValue* propval; bool show_debug_info; while(prop) { propval = NULL; show_debug_info = bool (prop->flag & PROP_DEBUG); switch(prop->type) { case GPROP_BOOL: { propval = new CBoolValue((bool)(prop->data != 0)); gameobj->SetProperty(prop->name,propval); //promp->poin= &prop->data; break; } case GPROP_INT: { propval = new CIntValue((int)prop->data); gameobj->SetProperty(prop->name,propval); break; } case GPROP_FLOAT: { //prop->poin= &prop->data; float floatprop = *((float*)&prop->data); propval = new CFloatValue(floatprop); gameobj->SetProperty(prop->name,propval); } break; case GPROP_STRING: { //prop->poin= callocN(MAX_PROPSTRING, "property string"); propval = new CStringValue((char*)prop->poin,""); gameobj->SetProperty(prop->name,propval); break; } case GPROP_TIME: { float floatprop = *((float*)&prop->data); CValue* timeval = new CFloatValue(floatprop); // set a subproperty called 'timer' so that // we can register the replica of this property // at the time a game object is replicated (AddObjectActuator triggers this) CValue *bval = new CBoolValue(true); timeval->SetProperty("timer",bval); bval->Release(); if (isInActiveLayer) { timemgr->AddTimeProperty(timeval); } propval = timeval; gameobj->SetProperty(prop->name,timeval); } default: { // todo make an assert etc. } } if (propval) { if (show_debug_info) { scene->AddDebugProperty(gameobj,STR_String(prop->name)); } // done with propval, release it propval->Release(); } #ifdef WITH_PYTHON /* Warn if we double up on attributes, this isnt quite right since it wont find inherited attributes however there arnt many */ for(PyAttributeDef *attrdef = KX_GameObject::Attributes; attrdef->m_name; attrdef++) { if(strcmp(prop->name, attrdef->m_name)==0) { printf("Warning! user defined property name \"%s\" is also a python attribute for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); break; } } for(PyMethodDef *methdef = KX_GameObject::Methods; methdef->ml_name; methdef++) { if(strcmp(prop->name, methdef->ml_name)==0) { printf("Warning! user defined property name \"%s\" is also a python method for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); break; } } /* end warning check */ #endif // WITH_PYTHON prop = prop->next; } // check if state needs to be debugged if (object->scaflag & OB_DEBUGSTATE) { // reserve name for object state scene->AddDebugProperty(gameobj,STR_String("__state__")); } /* Font Objects need to 'copy' the Font Object data body to ["Text"] */ if (object->type == OB_FONT) { BL_ConvertTextProperty(object, (KX_FontObject *)gameobj, timemgr, scene, isInActiveLayer); } }
bool SCA_PropertySensor::CheckPropertyCondition() { m_recentresult=false; bool result=false; bool reverse = false; switch (m_checktype) { case KX_PROPSENSOR_NOTEQUAL: reverse = true; case KX_PROPSENSOR_EQUAL: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const STR_String& testprop = orgprop->GetText(); // Force strings to upper case, to avoid confusion in // bool tests. It's stupid the prop's identity is lost // on the way here... if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) { m_checkpropval.Upper(); } result = (testprop == m_checkpropval); /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000" * this could be made into a generic Value class function for comparing values with a string. */ if (result==false && dynamic_cast<CFloatValue *>(orgprop) != NULL) { float f; if (EOF == sscanf(m_checkpropval.ReadPtr(), "%f", &f)) { //error } else { result = (f == ((CFloatValue *)orgprop)->GetFloat()); } } /* end patch */ } orgprop->Release(); if (reverse) result = !result; break; } case KX_PROPSENSOR_EXPRESSION: { /* if (m_rightexpr) { CValue* resultval = m_rightexpr->Calculate(); if (resultval->IsError()) { int i=0; STR_String errortest = resultval->GetText(); printf(errortest); } else { result = resultval->GetNumber() != 0; } } */ break; } case KX_PROPSENSOR_INTERVAL: { //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); //if (orgprop) //{ if (m_range_expr) { CValue* vallie = m_range_expr->Calculate(); if (vallie) { const STR_String& errtext = vallie->GetText(); if (&errtext == &CBoolValue::sTrueString) { result = true; } else { if (vallie->IsError()) { //printf (errtext.ReadPtr()); } } vallie->Release(); } } //} //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */ break; } case KX_PROPSENSOR_CHANGED: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { if (m_previoustext != orgprop->GetText()) { m_previoustext = orgprop->GetText(); result = true; } } orgprop->Release(); //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */ break; } default: ; /* error */ } //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED //see Game Engine bugtracker [ #3809 ] if (m_checktype != KX_PROPSENSOR_CHANGED) { m_recentresult=result; } else { m_recentresult=result;//true; } return result; }
bool SCA_PropertyActuator::Update() { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) return false; // do nothing on negative events CValue* propowner = GetParent(); CParser parser; parser.SetContext( propowner->AddRef()); CExpression* userexpr= NULL; if (m_type==KX_ACT_PROP_TOGGLE) { /* dont use */ CValue* newval; CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { newval = new CBoolValue((oldprop->GetNumber()==0.0) ? true:false); oldprop->SetValue(newval); } else { /* as not been assigned, evaluate as false, so assign true */ newval = new CBoolValue(true); propowner->SetProperty(m_propname,newval); } newval->Release(); } else if ((userexpr = parser.ProcessText(m_exprtxt))) { switch (m_type) { case KX_ACT_PROP_ASSIGN: { CValue* newval = userexpr->Calculate(); CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_propname,newval); } newval->Release(); break; } case KX_ACT_PROP_ADD: { CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { // int waarde = (int)oldprop->GetNumber(); /*unused*/ CExpression* expr = new COperator2Expr(VALUE_ADD_OPERATOR,new CConstExpr(oldprop->AddRef()), userexpr->AddRef()); CValue* newprop = expr->Calculate(); oldprop->SetValue(newprop); newprop->Release(); expr->Release(); } break; } case KX_ACT_PROP_COPY: { if (m_sourceObj) { CValue* copyprop = m_sourceObj->GetProperty(m_exprtxt); if (copyprop) { CValue *val = copyprop->GetReplica(); GetParent()->SetProperty( m_propname, val); val->Release(); } } break; } /* case KX_ACT_PROP_TOGGLE: */ /* accounted for above, no need for userexpr */ default: { } } userexpr->Release(); } return result; }
bool BL_ShapeActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool keepgoing = true; bool wrap = false; bool apply=true; int priority; float newweight; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; if (bNegativeEvent) { if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; } } /* This action can only be attached to a deform object */ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); float length = m_endframe - m_startframe; priority = m_priority; /* Determine pre-incrementation behaviour and set appropriate flags */ switch (m_playtype){ case ACT_ACTION_MOTION: if (bNegativeEvent){ keepgoing=false; apply=false; }; break; case ACT_ACTION_FROM_PROP: if (bNegativeEvent){ apply=false; keepgoing=false; } break; case ACT_ACTION_LOOP_END: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; m_localtime = m_startframe; m_starttime = curtime; } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; } break; case ACT_ACTION_LOOP_STOP: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_KEYUP; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_LOCKINPUT; keepgoing=false; apply=false; } break; case ACT_ACTION_PINGPONG: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; case ACT_ACTION_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_PINGPONG: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)) m_localtime = m_endframe; else m_localtime = m_startframe; m_flag &= ~ACT_FLAG_LOCKINPUT; m_flag ^= ACT_FLAG_REVERSE; //flip direction keepgoing = false; } break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0f; /* Apply the pose if necessary*/ if (apply) { /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); Key *key = NULL; if (shape_deformer) key = shape_deformer->GetKey(); if (!key) { // this could happen if the mesh was changed in the middle of an action // and the new mesh has no key, stop the action keepgoing = false; } else { ListBase tchanbase= {NULL, NULL}; if (m_blendin && m_blendframe==0.0f){ // this is the start of the blending, remember the startup shape obj->GetShape(m_blendshape); m_blendstart = curtime; } KeyBlock *kb; // We go through and clear out the keyblocks so there isn't any interference // from other shape actions for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next) kb->curval = 0.f; animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime); // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell if (0) { // XXX !execute_ipochannels(&tchanbase)) { // no update, this is possible if action does not match the keys, stop the action keepgoing = false; } else { // the key have changed, apply blending if needed if (m_blendin && (m_blendframe<m_blendin)){ newweight = (m_blendframe/(float)m_blendin); BlendShape(key, 1.0f - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; } m_lastUpdate = m_localtime; } BLI_freelistN(&tchanbase); } } else{ m_blendframe = 0.0f; } } if (!keepgoing){ m_blendframe = 0.0f; } return keepgoing; };
bool SCA_PropertySensor::CheckPropertyCondition() { m_recentresult=false; bool result=false; bool reverse = false; switch (m_checktype) { case KX_PROPSENSOR_NOTEQUAL: reverse = true; /* fall-through */ case KX_PROPSENSOR_EQUAL: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const std::string& testprop = orgprop->GetText(); // Force strings to upper case, to avoid confusion in // bool tests. It's stupid the prop's identity is lost // on the way here... if ((testprop == CBoolValue::sTrueString) || (testprop == CBoolValue::sFalseString)) { boost::to_upper(m_checkpropval); } result = (testprop == m_checkpropval); /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000" * this could be made into a generic Value class function for comparing values with a string. */ if (result==false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) { float f = std::stof(m_checkpropval); result = (f == ((CFloatValue *)orgprop)->GetFloat()); } /* end patch */ } orgprop->Release(); if (reverse) result = !result; break; } case KX_PROPSENSOR_EXPRESSION: { break; } case KX_PROPSENSOR_INTERVAL: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const float min = std::stof(m_checkpropval); const float max = std::stof(m_checkpropmaxval); float val; if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = std::stof(orgprop->GetText()); } else { val = orgprop->GetNumber(); } result = (min <= val) && (val <= max); } orgprop->Release(); break; } case KX_PROPSENSOR_CHANGED: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { if (m_previoustext != orgprop->GetText()) { m_previoustext = orgprop->GetText(); result = true; } } orgprop->Release(); break; } case KX_PROPSENSOR_LESSTHAN: reverse = true; /* fall-through */ case KX_PROPSENSOR_GREATERTHAN: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const float ref = std::stof(m_checkpropval); float val; if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = std::stof(orgprop->GetText()); } else { val = orgprop->GetNumber(); } if (reverse) { result = val < ref; } else { result = val > ref; } } orgprop->Release(); break; } default: ; /* error */ } //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED //see Game Engine bugtracker [ #3809 ] m_recentresult = result; return result; }