fixing some issues: force needs to wake up objects, property sensor issue, island...
[blender.git] / source / gameengine / GameLogic / SCA_PropertySensor.cpp
1 /**
2  * Property sensor
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include <iostream>
36 #include "SCA_PropertySensor.h"
37 #include "Operator2Expr.h"
38 #include "ConstExpr.h"
39 #include "InputParser.h"
40 #include "StringValue.h"
41 #include "SCA_EventManager.h"
42 #include "SCA_LogicManager.h"
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
49                                                                          SCA_IObject* gameobj,
50                                                                          const STR_String& propname,
51                                                                          const STR_String& propval,
52                                                                          const STR_String& propmaxval,
53                                                                          KX_PROPSENSOR_TYPE checktype,
54                                                                          PyTypeObject* T )
55         : SCA_ISensor(gameobj,eventmgr,T),
56           m_checktype(checktype),
57           m_checkpropval(propval),
58           m_checkpropmaxval(propmaxval),
59           m_checkpropname(propname),
60           m_lastresult(false),
61           m_range_expr(NULL)
62 {
63         m_recentresult=false;
64         //CParser pars;
65         //pars.SetContext(this->AddRef());
66         //CValue* resultval = m_rightexpr->Calculate();
67
68         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
69         if (orgprop)
70         {
71                 m_previoustext = orgprop->GetText();
72                 orgprop->Release();
73         }
74
75         if (m_checktype==KX_PROPSENSOR_INTERVAL)
76         {
77                 PrecalculateRangeExpression();
78         }
79
80 }
81
82 void SCA_PropertySensor::PrecalculateRangeExpression()
83 {
84                 CParser pars;
85                 pars.SetContext(this->AddRef());
86                 STR_String checkstr = "(" + m_checkpropval + " <= " 
87                                                         + m_checkpropname + ") && ( " 
88                                                         + m_checkpropname + " <= " 
89                                                         + m_checkpropmaxval;
90
91                 m_range_expr = pars.ProcessText(checkstr);
92 }
93
94
95
96 CValue* SCA_PropertySensor::GetReplica()
97 {
98         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
99         // m_range_expr must be recalculated on replica!
100         CValue::AddDataToReplica(replica);
101
102         replica->m_range_expr = NULL;
103         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
104         {
105                 replica->PrecalculateRangeExpression();
106         }
107         
108         
109         return replica;
110 }
111
112
113
114 bool SCA_PropertySensor::IsPositiveTrigger()
115 {
116         bool result = m_recentresult;//CheckPropertyCondition();
117         if (m_invert)
118                 result = !result;
119
120         return result;
121 }
122
123
124
125 SCA_PropertySensor::~SCA_PropertySensor()
126 {
127         //if (m_rightexpr)
128         //      m_rightexpr->Release();
129
130         if (m_range_expr)
131         {
132                 m_range_expr->Release();
133                 m_range_expr=NULL;
134         }
135
136 }
137
138
139
140 bool SCA_PropertySensor::Evaluate(CValue* event)
141 {
142         bool result = CheckPropertyCondition();
143         
144         if (m_lastresult!=result)
145         {
146                 m_lastresult = result;
147                 return true;
148         }
149
150         return false;
151 }
152
153
154 bool    SCA_PropertySensor::CheckPropertyCondition()
155 {
156
157         m_recentresult=false;
158         bool result=false;
159         bool reverse = false;
160         switch (m_checktype)
161         {
162         case KX_PROPSENSOR_NOTEQUAL:
163                 reverse = true;
164         case KX_PROPSENSOR_EQUAL:
165                 {
166                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
167                         if (orgprop)
168                         {
169                                 STR_String testprop = orgprop->GetText();
170                                 // Force strings to upper case, to avoid confusion in
171                                 // bool tests. It's stupid the prop's identity is lost
172                                 // on the way here...
173                                 if ((testprop == "TRUE") || (testprop == "FALSE")) {
174                                         STR_String checkprop = m_checkpropval;
175                                         checkprop.Upper();
176                                         result = (testprop == checkprop);
177                                 } else {
178                                         result = (orgprop->GetText() == m_checkpropval);
179                                 }
180                                 orgprop->Release();
181
182                         }
183
184                         if (reverse)
185                                 result = !result;
186                         break;
187
188                 }
189
190         case KX_PROPSENSOR_EXPRESSION:
191                 {
192                         /*
193                         if (m_rightexpr)
194                         {
195                                 CValue* resultval = m_rightexpr->Calculate();
196                                 if (resultval->IsError())
197                                 {
198                                         int i=0;
199                                         STR_String errortest = resultval->GetText();
200                                         printf(errortest);
201
202                                 } else
203                                 {
204                                         result = resultval->GetNumber() != 0;
205                                 }
206                         }
207                         */
208                         break;
209                 }
210         case KX_PROPSENSOR_INTERVAL:
211                 {
212                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
213                         //if (orgprop)
214                         //{
215                                 if (m_range_expr)
216                                 {
217                                         CValue* vallie = m_range_expr->Calculate();
218                                         if (vallie)
219                                         {
220                                                 STR_String errtext = vallie->GetText();
221                                                 if (errtext == "TRUE")
222                                                 {
223                                                         result = true;
224                                                 } else
225                                                 {
226                                                         if (vallie->IsError())
227                                                         {
228                                                                 //printf (errtext.ReadPtr());
229                                                         } 
230                                                 }
231                                                 
232                                                 vallie->Release();
233                                         }
234                                 }
235
236                                 
237                         //}
238                         
239                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
240
241                 break;
242                 }
243         case KX_PROPSENSOR_CHANGED:
244                 {
245                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
246                                 
247                         if (orgprop)
248                         {
249                                 if (m_previoustext != orgprop->GetText())
250                                 {
251                                         m_previoustext = orgprop->GetText();
252                                         result = true;
253                                 }
254                                 orgprop->Release();
255                         }
256
257                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
258                         break;
259                 }
260         default:
261                 ; /* error */
262         }
263
264         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
265         //see Game Engine bugtracker [ #3809 ]
266         if (m_checktype != KX_PROPSENSOR_CHANGED)
267         {
268                 m_recentresult=result;
269         } else
270         {
271                 m_recentresult=result;//true;
272         }
273         return result;
274 }
275
276 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
277 {
278         return  GetParent()->FindIdentifier(identifiername);
279 }
280
281 bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop)
282 {
283         bool result = true;
284         /*  There is no type checking at this moment, unfortunately...           */
285         return result;
286 }
287
288 /* ------------------------------------------------------------------------- */
289 /* Python functions                                                          */
290 /* ------------------------------------------------------------------------- */
291
292 /* Integration hooks ------------------------------------------------------- */
293 PyTypeObject SCA_PropertySensor::Type = {
294         PyObject_HEAD_INIT(&PyType_Type)
295         0,
296         "SCA_PropertySensor",
297         sizeof(SCA_PropertySensor),
298         0,
299         PyDestructor,
300         0,
301         __getattr,
302         __setattr,
303         0, //&MyPyCompare,
304         __repr,
305         0, //&cvalue_as_number,
306         0,
307         0,
308         0,
309         0
310 };
311
312 PyParentObject SCA_PropertySensor::Parents[] = {
313         &SCA_PropertySensor::Type,
314         &SCA_ISensor::Type,
315         &SCA_ILogicBrick::Type,
316         &CValue::Type,
317         NULL
318 };
319
320 PyMethodDef SCA_PropertySensor::Methods[] = {
321         {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, GetType_doc},
322         {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, SetType_doc},
323         {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
324         {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
325         {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, GetValue_doc},
326         {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, SetValue_doc},
327         {NULL,NULL} //Sentinel
328 };
329
330 PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) {
331         _getattr_up(SCA_ISensor); /* implicit return! */
332 }
333
334 /* 1. getType */
335 char SCA_PropertySensor::GetType_doc[] = 
336 "getType()\n"
337 "\tReturns the type of check this sensor performs.\n";
338 PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
339 {
340         return PyInt_FromLong(m_checktype);
341 }
342
343 /* 2. setType */
344 char SCA_PropertySensor::SetType_doc[] = 
345 "setType(type)\n"
346 "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
347 "\t        KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
348 "\t        or KX_PROPSENSOR_EXPRESSION.\n"
349 "\tSet the type of check to perform.\n";
350 PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds) 
351 {
352         int typeArg;
353         
354         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
355                 return NULL;
356         }
357         
358         if ( (typeArg > KX_PROPSENSOR_NODEF) 
359                  && (typeArg < KX_PROPSENSOR_MAX) ) {
360                 m_checktype =  typeArg;
361         }
362         
363         Py_Return;
364 }
365
366 /* 3. getProperty */
367 char SCA_PropertySensor::GetProperty_doc[] = 
368 "getProperty()\n"
369 "\tReturn the property with which the sensor operates.\n";
370 PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
371 {
372         return PyString_FromString(m_checkpropname);
373 }
374
375 /* 4. setProperty */
376 char SCA_PropertySensor::SetProperty_doc[] = 
377 "setProperty(name)\n"
378 "\t- name: string\n"
379 "\tSets the property with which to operate. If there is no property\n"
380 "\tof this name, the call is ignored.\n";
381 PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
382 {
383         /* We should query whether the name exists. Or should we create a prop   */
384         /* on the fly?                                                           */
385         char *propNameArg = NULL;
386
387         if (!PyArg_ParseTuple(args, "s", &propNameArg)) {
388                 return NULL;
389         }
390
391         if (FindIdentifier(STR_String(propNameArg))) {
392                 m_checkpropname = propNameArg;
393         } else {
394                 ; /* error: bad property name */
395         }
396
397         Py_Return;
398 }
399
400 /* 5. getValue */
401 char SCA_PropertySensor::GetValue_doc[] = 
402 "getValue()\n"
403 "\tReturns the value with which the sensor operates.\n";
404 PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) 
405 {
406         return PyString_FromString(m_checkpropval);
407 }
408
409 /* 6. setValue */
410 char SCA_PropertySensor::SetValue_doc[] = 
411 "setValue(value)\n"
412 "\t- value: string\n"
413 "\tSet the value with which the sensor operates. If the value\n"
414 "\tis not compatible with the type of the property, the subsequent\n"
415 "\t action is ignored.\n";
416 PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) 
417 {
418         /* Here, we need to check whether the value is 'valid' for this property.*/
419         /* We know that the property exists, or is NULL.                         */
420         char *propValArg = NULL;
421
422         if(!PyArg_ParseTuple(args, "s", &propValArg)) {
423                 return NULL;
424         }
425
426         if (validValueForProperty(propValArg, m_checkpropname)) {
427                 m_checkpropval = propValArg;
428         }       
429
430         Py_Return;
431 }
432
433 /* eof */