fix for struct definition building with msvc2008 and some style cleanup.
[blender-staging.git] / source / gameengine / Ketsji / KX_ObjectActuator.cpp
1 /*
2  * Do translation/rotation actions
3  *
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 /** \file gameengine/Ketsji/KX_ObjectActuator.cpp
32  *  \ingroup ketsji
33  */
34
35
36 #include "KX_ObjectActuator.h"
37 #include "KX_GameObject.h"
38 #include "KX_PyMath.h" // For PyVecTo - should this include be put in PyObjectPlus?
39 #include "KX_IPhysicsController.h"
40
41 /* ------------------------------------------------------------------------- */
42 /* Native functions                                                          */
43 /* ------------------------------------------------------------------------- */
44
45 KX_ObjectActuator::
46 KX_ObjectActuator(
47         SCA_IObject* gameobj,
48         KX_GameObject* refobj,
49         const MT_Vector3& force,
50         const MT_Vector3& torque,
51         const MT_Vector3& dloc,
52         const MT_Vector3& drot,
53         const MT_Vector3& linV,
54         const MT_Vector3& angV,
55         const short damping,
56         const KX_LocalFlags& flag
57 ) : 
58         SCA_IActuator(gameobj, KX_ACT_OBJECT),
59         m_force(force),
60         m_torque(torque),
61         m_dloc(dloc),
62         m_drot(drot),
63         m_linear_velocity(linV),
64         m_angular_velocity(angV),
65         m_linear_length2(0.0),
66         m_current_linear_factor(0.0),
67         m_current_angular_factor(0.0),
68         m_damping(damping),
69         m_previous_error(0.0,0.0,0.0),
70         m_error_accumulator(0.0,0.0,0.0),
71         m_bitLocalFlag (flag),
72         m_reference(refobj),
73         m_active_combined_velocity (false),
74         m_linear_damping_active(false),
75         m_angular_damping_active(false)
76 {
77         if (m_bitLocalFlag.ServoControl)
78         {
79                 // in servo motion, the force is local if the target velocity is local
80                 m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity;
81
82                 m_pid = m_torque;
83         }
84         if (m_bitLocalFlag.CharacterMotion)
85         {
86                 KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
87
88                 if (!parent->GetPhysicsController() || !parent->GetPhysicsController()->IsCharacter())
89                 {
90                         printf("Character motion enabled on non-character object (%s), falling back to simple motion.\n", parent->GetName().Ptr());
91                         m_bitLocalFlag.CharacterMotion = false;
92                 }
93         }
94         if (m_reference)
95                 m_reference->RegisterActuator(this);
96         UpdateFuzzyFlags();
97 }
98
99 KX_ObjectActuator::~KX_ObjectActuator()
100 {
101         if (m_reference)
102                 m_reference->UnregisterActuator(this);
103 }
104
105 bool KX_ObjectActuator::Update()
106 {
107         
108         bool bNegativeEvent = IsNegativeEvent();
109         RemoveAllEvents();
110                 
111         KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent()); 
112
113         if (bNegativeEvent) {
114                 // If we previously set the linear velocity we now have to inform
115                 // the physics controller that we no longer wish to apply it and that
116                 // it should reconcile the externally set velocity with it's 
117                 // own velocity.
118                 if (m_active_combined_velocity) {
119                         if (parent)
120                                 parent->ResolveCombinedVelocities(
121                                                 m_linear_velocity,
122                                                 m_angular_velocity,
123                                                 (m_bitLocalFlag.LinearVelocity) != 0,
124                                                 (m_bitLocalFlag.AngularVelocity) != 0
125                                         );
126                         m_active_combined_velocity = false;
127                 }
128
129                 // Explicitly stop the movement if we're using character motion
130                 if (m_bitLocalFlag.CharacterMotion) {
131                         MT_Vector3 vec(0.0, 0.0, 0.0);
132                         parent->GetPhysicsController()->SetWalkDirection(vec, true);
133                 }
134
135                 m_linear_damping_active = false;
136                 m_angular_damping_active = false;
137                 m_error_accumulator.setValue(0.0,0.0,0.0);
138                 m_previous_error.setValue(0.0,0.0,0.0);
139                 return false; 
140
141         } else if (parent)
142         {
143                 if (m_bitLocalFlag.ServoControl) 
144                 {
145                         // In this mode, we try to reach a target speed using force
146                         // As we don't know the friction, we must implement a generic 
147                         // servo control to achieve the speed in a configurable
148                         // v = current velocity
149                         // V = target velocity
150                         // e = V-v = speed error
151                         // dt = time interval since previous update
152                         // I = sum(e(t)*dt)
153                         // dv = e(t) - e(t-1)
154                         // KP, KD, KI : coefficient
155                         // F = KP*e+KI*I+KD*dv
156                         MT_Scalar mass = parent->GetMass();
157                         if (mass < MT_EPSILON)
158                                 return false;
159                         MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
160                         if (m_reference)
161                         {
162                                 const MT_Point3& mypos = parent->NodeGetWorldPosition();
163                                 const MT_Point3& refpos = m_reference->NodeGetWorldPosition();
164                                 MT_Point3 relpos;
165                                 relpos = (mypos-refpos);
166                                 MT_Vector3 vel= m_reference->GetVelocity(relpos);
167                                 if (m_bitLocalFlag.LinearVelocity)
168                                         // must convert in local space
169                                         vel = parent->NodeGetWorldOrientation().transposed()*vel;
170                                 v -= vel;
171                         }
172                         MT_Vector3 e = m_linear_velocity - v;
173                         MT_Vector3 dv = e - m_previous_error;
174                         MT_Vector3 I = m_error_accumulator + e;
175
176                         m_force = m_pid.x()*e+m_pid.y()*I+m_pid.z()*dv;
177                         // to automatically adapt the PID coefficient to mass;
178                         m_force *= mass;
179                         if (m_bitLocalFlag.Torque) 
180                         {
181                                 if (m_force[0] > m_dloc[0])
182                                 {
183                                         m_force[0] = m_dloc[0];
184                                         I[0] = m_error_accumulator[0];
185                                 } else if (m_force[0] < m_drot[0])
186                                 {
187                                         m_force[0] = m_drot[0];
188                                         I[0] = m_error_accumulator[0];
189                                 }
190                         }
191                         if (m_bitLocalFlag.DLoc) 
192                         {
193                                 if (m_force[1] > m_dloc[1])
194                                 {
195                                         m_force[1] = m_dloc[1];
196                                         I[1] = m_error_accumulator[1];
197                                 } else if (m_force[1] < m_drot[1])
198                                 {
199                                         m_force[1] = m_drot[1];
200                                         I[1] = m_error_accumulator[1];
201                                 }
202                         }
203                         if (m_bitLocalFlag.DRot) 
204                         {
205                                 if (m_force[2] > m_dloc[2])
206                                 {
207                                         m_force[2] = m_dloc[2];
208                                         I[2] = m_error_accumulator[2];
209                                 } else if (m_force[2] < m_drot[2])
210                                 {
211                                         m_force[2] = m_drot[2];
212                                         I[2] = m_error_accumulator[2];
213                                 }
214                         }
215                         m_previous_error = e;
216                         m_error_accumulator = I;
217                         parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0);
218                 }
219                 else if (m_bitLocalFlag.CharacterMotion) {
220                         MT_Vector3 dir = m_dloc;
221
222                         if (m_bitLocalFlag.AddOrSetCharLoc) {
223                                 MT_Vector3 old_dir = parent->GetPhysicsController()->GetWalkDirection();
224
225                                 if (!old_dir.fuzzyZero()) {
226                                         MT_Scalar mag = old_dir.length();
227
228                                         dir = dir + old_dir;
229                                         if (!dir.fuzzyZero())
230                                                 dir = dir.normalized() * mag;
231                                 }
232                         }
233
234                         // We always want to set the walk direction since a walk direction of (0, 0, 0) should stop the character
235                         parent->GetPhysicsController()->SetWalkDirection(dir, (m_bitLocalFlag.DLoc) != 0);
236
237                         if (!m_bitLocalFlag.ZeroDRot)
238                         {
239                                 parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
240                         }
241                         if (m_bitLocalFlag.CharacterJump)
242                         {
243                                 parent->GetPhysicsController()->Jump();
244                         }
245                 }
246                 else {
247                         if (!m_bitLocalFlag.ZeroForce)
248                         {
249                                 parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
250                         }
251                         if (!m_bitLocalFlag.ZeroTorque)
252                         {
253                                 parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
254                         }
255                         if (!m_bitLocalFlag.ZeroDLoc)
256                         {
257                                 parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
258                         }
259                         if (!m_bitLocalFlag.ZeroDRot)
260                         {
261                                 parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
262                         }
263                         if (!m_bitLocalFlag.ZeroLinearVelocity)
264                         {
265                                 if (m_bitLocalFlag.AddOrSetLinV) {
266                                         parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
267                                 } else {
268                                         m_active_combined_velocity = true;
269                                         if (m_damping > 0) {
270                                                 MT_Vector3 linV;
271                                                 if (!m_linear_damping_active) {
272                                                         // delta and the start speed (depends on the existing speed in that direction)
273                                                         linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
274                                                         // keep only the projection along the desired direction
275                                                         m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
276                                                         m_linear_damping_active = true;
277                                                 }
278                                                 if (m_current_linear_factor < 1.0)
279                                                         m_current_linear_factor += 1.0/m_damping;
280                                                 if (m_current_linear_factor > 1.0)
281                                                         m_current_linear_factor = 1.0;
282                                                 linV = m_current_linear_factor * m_linear_velocity;
283                                                 parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
284                                         } else {
285                                                 parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
286                                         }
287                                 }
288                         }
289                         if (!m_bitLocalFlag.ZeroAngularVelocity)
290                         {
291                                 m_active_combined_velocity = true;
292                                 if (m_damping > 0) {
293                                         MT_Vector3 angV;
294                                         if (!m_angular_damping_active) {
295                                                 // delta and the start speed (depends on the existing speed in that direction)
296                                                 angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
297                                                 // keep only the projection along the desired direction
298                                                 m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
299                                                 m_angular_damping_active = true;
300                                         }
301                                         if (m_current_angular_factor < 1.0)
302                                                 m_current_angular_factor += 1.0/m_damping;
303                                         if (m_current_angular_factor > 1.0)
304                                                 m_current_angular_factor = 1.0;
305                                         angV = m_current_angular_factor * m_angular_velocity;
306                                         parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
307                                 } else {
308                                         parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
309                                 }
310                         }
311                 }
312                 
313         }
314         return true;
315 }
316
317
318
319 CValue* KX_ObjectActuator::GetReplica()
320 {
321         KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName());
322         replica->ProcessReplica();
323
324         return replica;
325 }
326
327 void KX_ObjectActuator::ProcessReplica()
328 {
329         SCA_IActuator::ProcessReplica();
330         if (m_reference)
331                 m_reference->RegisterActuator(this);
332 }
333
334 bool KX_ObjectActuator::UnlinkObject(SCA_IObject* clientobj)
335 {
336         if (clientobj == (SCA_IObject*)m_reference)
337         {
338                 // this object is being deleted, we cannot continue to use it as reference.
339                 m_reference = NULL;
340                 return true;
341         }
342         return false;
343 }
344
345 void KX_ObjectActuator::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map)
346 {
347         void **h_obj = (*obj_map)[m_reference];
348         if (h_obj) {
349                 if (m_reference)
350                         m_reference->UnregisterActuator(this);
351                 m_reference = (KX_GameObject*)(*h_obj);
352                 m_reference->RegisterActuator(this);
353         }
354 }
355
356 /* some 'standard' utilities... */
357 bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type)
358 {
359         bool res = false;
360         res = (type > KX_OBJECT_ACT_NODEF) && (type < KX_OBJECT_ACT_MAX);
361         return res;
362 }
363
364 #ifdef WITH_PYTHON
365
366 /* ------------------------------------------------------------------------- */
367 /* Python functions                                                          */
368 /* ------------------------------------------------------------------------- */
369
370 /* Integration hooks ------------------------------------------------------- */
371 PyTypeObject KX_ObjectActuator::Type = {
372         PyVarObject_HEAD_INIT(NULL, 0)
373         "KX_ObjectActuator",
374         sizeof(PyObjectPlus_Proxy),
375         0,
376         py_base_dealloc,
377         0,
378         0,
379         0,
380         0,
381         py_base_repr,
382         0,0,0,0,0,0,0,0,0,
383         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
384         0,0,0,0,0,0,0,
385         Methods,
386         0,
387         0,
388         &SCA_IActuator::Type,
389         0,0,0,0,0,0,
390         py_base_new
391 };
392
393 PyMethodDef KX_ObjectActuator::Methods[] = {
394         {NULL,NULL} //Sentinel
395 };
396
397 PyAttributeDef KX_ObjectActuator::Attributes[] = {
398         KX_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, PyUpdateFuzzyFlags),
399         KX_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force),
400         KX_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, PyUpdateFuzzyFlags),
401         KX_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque),
402         KX_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, PyUpdateFuzzyFlags),
403         KX_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc),
404         KX_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, PyUpdateFuzzyFlags),
405         KX_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot),
406 #ifdef USE_MATHUTILS
407         KX_PYATTRIBUTE_RW_FUNCTION("linV", KX_ObjectActuator, pyattr_get_linV, pyattr_set_linV),
408         KX_PYATTRIBUTE_RW_FUNCTION("angV", KX_ObjectActuator, pyattr_get_angV, pyattr_set_angV),
409 #else
410         KX_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, PyUpdateFuzzyFlags),
411         KX_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, PyUpdateFuzzyFlags),
412 #endif
413         KX_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity),
414         KX_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity),
415         KX_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping),
416         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX),
417         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY),
418         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ),
419         KX_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, PyCheckPid),
420         KX_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator,pyattr_get_reference,pyattr_set_reference),
421         { NULL }        //Sentinel
422 };
423
424 /* Attribute get/set functions */
425
426 #ifdef USE_MATHUTILS
427
428 /* These require an SGNode */
429 #define MATHUTILS_VEC_CB_LINV 1
430 #define MATHUTILS_VEC_CB_ANGV 2
431
432 static unsigned char mathutils_kxobactu_vector_cb_index = -1; /* index for our callbacks */
433
434 static int mathutils_obactu_generic_check(BaseMathObject *bmo)
435 {
436         KX_ObjectActuator* self = static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
437         if (self == NULL)
438                 return -1;
439
440         return 0;
441 }
442
443 static int mathutils_obactu_vector_get(BaseMathObject *bmo, int subtype)
444 {
445         KX_ObjectActuator* self = static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
446         if (self == NULL)
447                 return -1;
448
449         switch (subtype) {
450                 case MATHUTILS_VEC_CB_LINV:
451                         self->m_linear_velocity.getValue(bmo->data);
452                         break;
453                 case MATHUTILS_VEC_CB_ANGV:
454                         self->m_angular_velocity.getValue(bmo->data);
455                         break;
456         }
457
458         return 0;
459 }
460
461 static int mathutils_obactu_vector_set(BaseMathObject *bmo, int subtype)
462 {
463         KX_ObjectActuator* self = static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
464         if (self == NULL)
465                 return -1;
466
467         switch (subtype) {
468                 case MATHUTILS_VEC_CB_LINV:
469                         self->m_linear_velocity.setValue(bmo->data);
470                         break;
471                 case MATHUTILS_VEC_CB_ANGV:
472                         self->m_angular_velocity.setValue(bmo->data);
473                         break;
474         }
475
476         return 0;
477 }
478
479 static int mathutils_obactu_vector_get_index(BaseMathObject *bmo, int subtype, int index)
480 {
481         /* lazy, avoid repeteing the case statement */
482         if (mathutils_obactu_vector_get(bmo, subtype) == -1)
483                 return -1;
484         return 0;
485 }
486
487 static int mathutils_obactu_vector_set_index(BaseMathObject *bmo, int subtype, int index)
488 {
489         float f = bmo->data[index];
490
491         /* lazy, avoid repeteing the case statement */
492         if (mathutils_obactu_vector_get(bmo, subtype) == -1)
493                 return -1;
494
495         bmo->data[index] = f;
496         return mathutils_obactu_vector_set(bmo, subtype);
497 }
498
499 Mathutils_Callback mathutils_obactu_vector_cb = {
500         mathutils_obactu_generic_check,
501         mathutils_obactu_vector_get,
502         mathutils_obactu_vector_set,
503         mathutils_obactu_vector_get_index,
504         mathutils_obactu_vector_set_index
505 };
506
507 PyObject *KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
508 {
509         return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV);
510 }
511
512 int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
513 {
514         KX_ObjectActuator* self = static_cast<KX_ObjectActuator*>(self_v);
515         if (!PyVecTo(value, self->m_linear_velocity))
516                 return PY_SET_ATTR_FAIL;
517
518         self->UpdateFuzzyFlags();
519
520         return PY_SET_ATTR_SUCCESS;
521 }
522
523 PyObject *KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
524 {
525         return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV);
526 }
527
528 int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
529 {
530         KX_ObjectActuator* self = static_cast<KX_ObjectActuator*>(self_v);
531         if (!PyVecTo(value, self->m_angular_velocity))
532                 return PY_SET_ATTR_FAIL;
533
534         self->UpdateFuzzyFlags();
535
536         return PY_SET_ATTR_SUCCESS;
537 }
538
539
540 void KX_ObjectActuator_Mathutils_Callback_Init(void)
541 {
542         // register mathutils callbacks, ok to run more then once.
543         mathutils_kxobactu_vector_cb_index = Mathutils_RegisterCallback(&mathutils_obactu_vector_cb);
544 }
545
546 #endif // USE_MATHUTILS
547
548 PyObject *KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
549 {
550         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
551         PyObject *retVal = PyList_New(3);
552
553         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[0]));
554         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[0]));
555         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.Torque));
556         
557         return retVal;
558 }
559
560 int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
561 {
562         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
563
564         PyObject *seq = PySequence_Fast(value, "");
565         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
566         {
567                 self->m_drot[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
568                 self->m_dloc[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
569                 self->m_bitLocalFlag.Torque = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0);
570
571                 if (!PyErr_Occurred())
572                 {
573                         Py_DECREF(seq);
574                         return PY_SET_ATTR_SUCCESS;
575                 }
576         }
577
578         Py_XDECREF(seq);
579
580         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
581         return PY_SET_ATTR_FAIL;
582 }
583
584 PyObject *KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
585 {
586         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
587         PyObject *retVal = PyList_New(3);
588
589         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[1]));
590         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[1]));
591         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DLoc));
592         
593         return retVal;
594 }
595
596 int     KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
597 {
598         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
599
600         PyObject *seq = PySequence_Fast(value, "");
601         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
602         {
603                 self->m_drot[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
604                 self->m_dloc[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
605                 self->m_bitLocalFlag.DLoc = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0);
606
607                 if (!PyErr_Occurred())
608                 {
609                         Py_DECREF(seq);
610                         return PY_SET_ATTR_SUCCESS;
611                 }
612         }
613
614         Py_XDECREF(seq);
615
616         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
617         return PY_SET_ATTR_FAIL;
618 }
619
620 PyObject *KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
621 {
622         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
623         PyObject *retVal = PyList_New(3);
624
625         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[2]));
626         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[2]));
627         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DRot));
628         
629         return retVal;
630 }
631
632 int     KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
633 {
634         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
635
636         PyObject *seq = PySequence_Fast(value, "");
637         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
638         {
639                 self->m_drot[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
640                 self->m_dloc[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
641                 self->m_bitLocalFlag.DRot = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0);
642
643                 if (!PyErr_Occurred())
644                 {
645                         Py_DECREF(seq);
646                         return PY_SET_ATTR_SUCCESS;
647                 }
648         }
649
650         Py_XDECREF(seq);
651
652         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
653         return PY_SET_ATTR_FAIL;
654 }
655
656 PyObject *KX_ObjectActuator::pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
657 {
658         KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self);
659         if (!actuator->m_reference)
660                 Py_RETURN_NONE;
661         
662         return actuator->m_reference->GetProxy();
663 }
664
665 int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
666 {
667         KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self);
668         KX_GameObject *refOb;
669         
670         if (!ConvertPythonToGameObject(value, &refOb, true, "actu.reference = value: KX_ObjectActuator"))
671                 return PY_SET_ATTR_FAIL;
672         
673         if (actuator->m_reference)
674                 actuator->m_reference->UnregisterActuator(actuator);
675         
676         if (refOb==NULL) {
677                 actuator->m_reference= NULL;
678         }
679         else {
680                 actuator->m_reference = refOb;
681                 actuator->m_reference->RegisterActuator(actuator);
682         }
683         
684         return PY_SET_ATTR_SUCCESS;
685 }
686
687 #endif // WITH_PYTHON
688
689 /* eof */