BGE patch: Add PyDoc for new logic bricks, set exception message on Py error, remove...
[blender.git] / source / gameengine / Converter / BL_ShapeActionActuator.cpp
1 /**
2 * $Id$
3 *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28 */
29
30 #if defined (__sgi)
31 #include <math.h>
32 #else
33 #include <cmath>
34 #endif
35
36 #include "SCA_LogicManager.h"
37 #include "BL_ShapeActionActuator.h"
38 #include "BL_ActionActuator.h"
39 #include "BL_ShapeDeformer.h"
40 #include "KX_GameObject.h"
41 #include "STR_HashedString.h"
42 #include "DNA_action_types.h"
43 #include "DNA_nla_types.h"
44 #include "DNA_actuator_types.h"
45 #include "BKE_action.h"
46 #include "DNA_armature_types.h"
47 #include "MEM_guardedalloc.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50 #include "MT_Matrix4x4.h"
51 #include "BKE_utildefines.h"
52
53 #ifdef HAVE_CONFIG_H
54 #include <config.h>
55 #endif
56
57 BL_ShapeActionActuator::~BL_ShapeActionActuator()
58 {
59 }
60
61 void BL_ShapeActionActuator::ProcessReplica()
62 {
63         m_localtime=m_startframe;
64         m_lastUpdate=-1;
65 }
66
67 void BL_ShapeActionActuator::SetBlendTime (float newtime)
68 {
69         m_blendframe = newtime;
70 }
71
72 CValue* BL_ShapeActionActuator::GetReplica() 
73 {
74         BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
75         replica->ProcessReplica();
76         
77         // this will copy properties and so on...
78         CValue::AddDataToReplica(replica);
79         return replica;
80 }
81
82 bool BL_ShapeActionActuator::ClampLocalTime()
83 {
84         if (m_startframe < m_endframe)  {
85                 if (m_localtime < m_startframe)
86                 {
87                         m_localtime = m_startframe;
88                         return true;
89                 } 
90                 else if (m_localtime > m_endframe)
91                 {
92                         m_localtime = m_endframe;
93                         return true;
94                 }
95         } else {
96                 if (m_localtime > m_startframe)
97                 {
98                         m_localtime = m_startframe;
99                         return true;
100                 }
101                 else if (m_localtime < m_endframe)
102                 {
103                         m_localtime = m_endframe;
104                         return true;
105                 }
106         }
107         return false;
108 }
109
110 void BL_ShapeActionActuator::SetStartTime(float curtime)
111 {
112         float direction = m_startframe < m_endframe ? 1.0 : -1.0;
113         
114         if (!(m_flag & ACT_FLAG_REVERSE))
115                 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
116         else
117                 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
118 }
119
120 void BL_ShapeActionActuator::SetLocalTime(float curtime)
121 {
122         float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
123         
124         if (m_endframe < m_startframe)
125                 delta_time = -delta_time;
126
127         if (!(m_flag & ACT_FLAG_REVERSE))
128                 m_localtime = m_startframe + delta_time;
129         else
130                 m_localtime = m_endframe - delta_time;
131 }
132
133 void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
134 {
135         vector<float>::const_iterator it;
136         float dstweight;
137         int i;
138         KeyBlock *kb;
139         
140         dstweight = 1.0F - srcweight;
141
142         for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
143                  kb && it != m_blendshape.end(); 
144                  kb = (KeyBlock*)kb->next, it++) {
145                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
146         }
147 }
148
149 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
150 {
151         bool bNegativeEvent = false;
152         bool bPositiveEvent = false;
153         bool keepgoing = true;
154         bool wrap = false;
155         bool apply=true;
156         int     priority;
157         float newweight;
158         
159         // result = true if animation has to be continued, false if animation stops
160         // maybe there are events for us in the queue !
161         if (frame)
162         {
163                 for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++)
164                 {
165                         if ((*i)->GetNumber() == 0.0f)
166                                 bNegativeEvent = true;
167                         else
168                                 bPositiveEvent= true;
169                         (*i)->Release();
170                 
171                 }
172                 m_events.clear();
173                 
174                 if (bPositiveEvent)
175                         m_flag |= ACT_FLAG_ACTIVE;
176                 
177                 if (bNegativeEvent)
178                 {
179                         if (!(m_flag & ACT_FLAG_ACTIVE))
180                                 return false;
181                         m_flag &= ~ACT_FLAG_ACTIVE;
182                 }
183         }
184         
185         /*      This action can only be attached to a deform object */
186         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
187         float length = m_endframe - m_startframe;
188         
189         priority = m_priority;
190         
191         /* Determine pre-incrementation behaviour and set appropriate flags */
192         switch (m_playtype){
193         case ACT_ACTION_MOTION:
194                 if (bNegativeEvent){
195                         keepgoing=false;
196                         apply=false;
197                 };
198                 break;
199         case ACT_ACTION_FROM_PROP:
200                 if (bNegativeEvent){
201                         apply=false;
202                         keepgoing=false;
203                 }
204                 break;
205         case ACT_ACTION_LOOP_END:
206                 if (bPositiveEvent){
207                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
208                                 m_flag &= ~ACT_FLAG_KEYUP;
209                                 m_flag &= ~ACT_FLAG_REVERSE;
210                                 m_flag |= ACT_FLAG_LOCKINPUT;
211                                 m_localtime = m_startframe;
212                                 m_starttime = curtime;
213                         }
214                 }
215                 if (bNegativeEvent){
216                         m_flag |= ACT_FLAG_KEYUP;
217                 }
218                 break;
219         case ACT_ACTION_LOOP_STOP:
220                 if (bPositiveEvent){
221                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
222                                 m_flag &= ~ACT_FLAG_REVERSE;
223                                 m_flag &= ~ACT_FLAG_KEYUP;
224                                 m_flag |= ACT_FLAG_LOCKINPUT;
225                                 SetStartTime(curtime);
226                         }
227                 }
228                 if (bNegativeEvent){
229                         m_flag |= ACT_FLAG_KEYUP;
230                         m_flag &= ~ACT_FLAG_LOCKINPUT;
231                         keepgoing=false;
232                         apply=false;
233                 }
234                 break;
235         case ACT_ACTION_FLIPPER:
236                 if (bPositiveEvent){
237                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
238                                 m_flag &= ~ACT_FLAG_REVERSE;
239                                 m_flag |= ACT_FLAG_LOCKINPUT;
240                                 SetStartTime(curtime);
241                         }
242                 }
243                 else if (bNegativeEvent){
244                         m_flag |= ACT_FLAG_REVERSE;
245                         m_flag &= ~ACT_FLAG_LOCKINPUT;
246                         SetStartTime(curtime);
247                 }
248                 break;
249         case ACT_ACTION_PLAY:
250                 if (bPositiveEvent){
251                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
252                                 m_flag &= ~ACT_FLAG_REVERSE;
253                                 m_localtime = m_starttime;
254                                 m_starttime = curtime;
255                                 m_flag |= ACT_FLAG_LOCKINPUT;
256                         }
257                 }
258                 break;
259         default:
260                 break;
261         }
262         
263         /* Perform increment */
264         if (keepgoing){
265                 if (m_playtype == ACT_ACTION_MOTION){
266                         MT_Point3       newpos;
267                         MT_Point3       deltapos;
268                         
269                         newpos = obj->NodeGetWorldPosition();
270                         
271                         /* Find displacement */
272                         deltapos = newpos-m_lastpos;
273                         m_localtime += (length/m_stridelength) * deltapos.length();
274                         m_lastpos = newpos;
275                 }
276                 else{
277                         SetLocalTime(curtime);
278                 }
279         }
280         
281         /* Check if a wrapping response is needed */
282         if (length){
283                 if (m_localtime < m_startframe || m_localtime > m_endframe)
284                 {
285                         m_localtime = m_startframe + fmod(m_localtime, length);
286                         wrap = true;
287                 }
288         }
289         else
290                 m_localtime = m_startframe;
291         
292         /* Perform post-increment tasks */
293         switch (m_playtype){
294         case ACT_ACTION_FROM_PROP:
295                 {
296                         CValue* propval = GetParent()->GetProperty(m_propname);
297                         if (propval)
298                                 m_localtime = propval->GetNumber();
299                         
300                         if (bNegativeEvent){
301                                 keepgoing=false;
302                         }
303                 }
304                 break;
305         case ACT_ACTION_MOTION:
306                 break;
307         case ACT_ACTION_LOOP_STOP:
308                 break;
309         case ACT_ACTION_FLIPPER:
310                 if (wrap){
311                         if (!(m_flag & ACT_FLAG_REVERSE)){
312                                 m_localtime=m_endframe;
313                                 //keepgoing = false;
314                         }
315                         else {
316                                 m_localtime=m_startframe;
317                                 keepgoing = false;
318                         }
319                 }
320                 break;
321         case ACT_ACTION_LOOP_END:
322                 if (wrap){
323                         if (m_flag & ACT_FLAG_KEYUP){
324                                 keepgoing = false;
325                                 m_localtime = m_endframe;
326                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
327                         }
328                         SetStartTime(curtime);
329                 }
330                 break;
331         case ACT_ACTION_PLAY:
332                 if (wrap){
333                         m_localtime = m_endframe;
334                         keepgoing = false;
335                         m_flag &= ~ACT_FLAG_LOCKINPUT;
336                 }
337                 break;
338         default:
339                 keepgoing = false;
340                 break;
341         }
342         
343         
344         if (bNegativeEvent)
345                 m_blendframe=0.0f;
346         
347         /* Apply the pose if necessary*/
348         if (apply) {
349
350                 /* Priority test */
351                 if (obj->SetActiveAction(this, priority, curtime)){
352                         Key *key = obj->GetKey();
353
354                         if (!key) {
355                                 // this could happen if the mesh was changed in the middle of an action
356                                 // and the new mesh has no key, stop the action
357                                 keepgoing = false;
358                         }
359                         else {
360                                 ListBase tchanbase= {NULL, NULL};
361                         
362                                 if (m_blendin && m_blendframe==0.0f){
363                                         // this is the start of the blending, remember the startup shape
364                                         obj->GetShape(m_blendshape);
365                                         m_blendstart = curtime;
366                                 }
367                                 // only interested in shape channel
368                                 extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
369                 
370                                 if (!execute_ipochannels(&tchanbase)) {
371                                         // no update, this is possible if action does not match the keys, stop the action
372                                         keepgoing = false;
373                                 } 
374                                 else {
375                                         // the key have changed, apply blending if needed
376                                         if (m_blendin && (m_blendframe<m_blendin)){
377                                                 newweight = (m_blendframe/(float)m_blendin);
378
379                                                 BlendShape(key, 1.0f - newweight);
380
381                                                 /* Increment current blending percentage */
382                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
383                                                 if (m_blendframe>m_blendin)
384                                                         m_blendframe = m_blendin;
385                                         }
386                                         m_lastUpdate = m_localtime;
387                                 }
388                                 BLI_freelistN(&tchanbase);
389                         }
390                 }
391                 else{
392                         m_blendframe = 0.0f;
393                 }
394         }
395         
396         if (!keepgoing){
397                 m_blendframe = 0.0f;
398         }
399         return keepgoing;
400 };
401
402 /* ------------------------------------------------------------------------- */
403 /* Python functions                                                          */
404 /* ------------------------------------------------------------------------- */
405
406 /* Integration hooks ------------------------------------------------------- */
407
408 PyTypeObject BL_ShapeActionActuator::Type = {
409         PyObject_HEAD_INIT(&PyType_Type)
410                 0,
411                 "BL_ShapeActionActuator",
412                 sizeof(BL_ShapeActionActuator),
413                 0,
414                 PyDestructor,
415                 0,
416                 __getattr,
417                 __setattr,
418                 0, //&MyPyCompare,
419                 __repr,
420                 0, //&cvalue_as_number,
421                 0,
422                 0,
423                 0,
424                 0
425 };
426
427 PyParentObject BL_ShapeActionActuator::Parents[] = {
428         &BL_ShapeActionActuator::Type,
429                 &SCA_IActuator::Type,
430                 &SCA_ILogicBrick::Type,
431                 &CValue::Type,
432                 NULL
433 };
434
435 PyMethodDef BL_ShapeActionActuator::Methods[] = {
436         {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, SetAction_doc},
437         {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, SetStart_doc},
438         {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc},
439         {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc},
440         {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc},
441         {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc},
442         {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
443         {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc},
444
445         {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_NOARGS, GetAction_doc},
446         {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_NOARGS, GetStart_doc},
447         {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_NOARGS, GetEnd_doc},
448         {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_NOARGS, GetBlendin_doc},
449         {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_NOARGS, GetPriority_doc},
450         {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_NOARGS, GetFrame_doc},
451         {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_NOARGS, GetProperty_doc},
452         {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_NOARGS, GetType_doc},        
453         {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_NOARGS, SetType_doc},
454         {NULL,NULL} //Sentinel
455 };
456
457 PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) {
458         _getattr_up(SCA_IActuator);
459 }
460
461 /*     setStart                                                              */
462 char BL_ShapeActionActuator::GetAction_doc[] = 
463 "getAction()\n"
464 "\tReturns a string containing the name of the current action.\n";
465
466 PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self) {
467         PyObject *result;
468         
469         if (m_action){
470                 result = Py_BuildValue("s", m_action->id.name+2);
471         }
472         else{
473                 Py_INCREF(Py_None);
474                 result = Py_None;
475         }
476         
477         return result;
478 }
479
480 /*     getProperty                                                             */
481 char BL_ShapeActionActuator::GetProperty_doc[] = 
482 "getProperty()\n"
483 "\tReturns the name of the property to be used in FromProp mode.\n";
484
485 PyObject* BL_ShapeActionActuator::PyGetProperty(PyObject* self) {
486         PyObject *result;
487         
488         result = Py_BuildValue("s", (const char *)m_propname);
489         
490         return result;
491 }
492
493 /*     getFrame                                                              */
494 char BL_ShapeActionActuator::GetFrame_doc[] = 
495 "getFrame()\n"
496 "\tReturns the current frame number.\n";
497
498 PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self) {
499         PyObject *result;
500         
501         result = Py_BuildValue("f", m_localtime);
502         
503         return result;
504 }
505
506 /*     getEnd                                                                */
507 char BL_ShapeActionActuator::GetEnd_doc[] = 
508 "getEnd()\n"
509 "\tReturns the last frame of the action.\n";
510
511 PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self) {
512         PyObject *result;
513         
514         result = Py_BuildValue("f", m_endframe);
515         
516         return result;
517 }
518
519 /*     getStart                                                              */
520 char BL_ShapeActionActuator::GetStart_doc[] = 
521 "getStart()\n"
522 "\tReturns the starting frame of the action.\n";
523
524 PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self) {
525         PyObject *result;
526         
527         result = Py_BuildValue("f", m_startframe);
528         
529         return result;
530 }
531
532 /*     getBlendin                                                            */
533 char BL_ShapeActionActuator::GetBlendin_doc[] = 
534 "getBlendin()\n"
535 "\tReturns the number of interpolation animation frames to be\n"
536 "\tgenerated when this actuator is triggered.\n";
537
538 PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self) {
539         PyObject *result;
540         
541         result = Py_BuildValue("f", m_blendin);
542         
543         return result;
544 }
545
546 /*     getPriority                                                           */
547 char BL_ShapeActionActuator::GetPriority_doc[] = 
548 "getPriority()\n"
549 "\tReturns the priority for this actuator.  Actuators with lower\n"
550 "\tPriority numbers will override actuators with higher numbers.\n";
551
552 PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self) {
553         PyObject *result;
554         
555         result = Py_BuildValue("i", m_priority);
556         
557         return result;
558 }
559
560 /*     setAction                                                             */
561 char BL_ShapeActionActuator::SetAction_doc[] = 
562 "setAction(action, (reset))\n"
563 "\t - action    : The name of the action to set as the current action.\n"
564 "\t               Should be an action with Shape channels.\n"
565 "\t - reset     : Optional parameter indicating whether to reset the\n"
566 "\t               blend timer or not.  A value of 1 indicates that the\n"
567 "\t               timer should be reset.  A value of 0 will leave it\n"
568 "\t               unchanged.  If reset is not specified, the timer will"
569 "\t                   be reset.\n";
570
571 PyObject* BL_ShapeActionActuator::PySetAction(PyObject* self, 
572                                                                                           PyObject* args, 
573                                                                                           PyObject* kwds) {
574         char *string;
575         int     reset = 1;
576
577         if (PyArg_ParseTuple(args,"s|i",&string, &reset))
578         {
579                 bAction *action;
580                 
581                 action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string));
582                 
583                 if (!action){
584                         /* NOTE!  Throw an exception or something */
585                         //                      printf ("setAction failed: Action not found\n", string);
586                 }
587                 else{
588                         m_action=action;
589                         if (reset)
590                                 m_blendframe = 0.f;
591                 }
592         }
593         else {
594                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
595                 return NULL;
596         }
597         
598         Py_INCREF(Py_None);
599         return Py_None;
600 }
601
602 /*     setStart                                                              */
603 char BL_ShapeActionActuator::SetStart_doc[] = 
604 "setStart(start)\n"
605 "\t - start     : Specifies the starting frame of the animation.\n";
606
607 PyObject* BL_ShapeActionActuator::PySetStart(PyObject* self, 
608                                                                                          PyObject* args, 
609                                                                                          PyObject* kwds) {
610         float start;
611         
612         if (PyArg_ParseTuple(args,"f",&start))
613         {
614                 m_startframe = start;
615         }
616         else {
617                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
618                 return NULL;
619         }
620         
621         Py_INCREF(Py_None);
622         return Py_None;
623 }
624
625 /*     setEnd                                                                */
626 char BL_ShapeActionActuator::SetEnd_doc[] = 
627 "setEnd(end)\n"
628 "\t - end       : Specifies the ending frame of the animation.\n";
629
630 PyObject* BL_ShapeActionActuator::PySetEnd(PyObject* self, 
631                                                                                    PyObject* args, 
632                                                                                    PyObject* kwds) {
633         float end;
634         
635         if (PyArg_ParseTuple(args,"f",&end))
636         {
637                 m_endframe = end;
638         }
639         else {
640                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
641                 return NULL;
642         }
643         
644         Py_INCREF(Py_None);
645         return Py_None;
646 }
647
648 /*     setBlendin                                                            */
649 char BL_ShapeActionActuator::SetBlendin_doc[] = 
650 "setBlendin(blendin)\n"
651 "\t - blendin   : Specifies the number of frames of animation to generate\n"
652 "\t               when making transitions between actions.\n";
653
654 PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self, 
655                                                                                            PyObject* args, 
656                                                                                            PyObject* kwds) {
657         float blendin;
658         
659         if (PyArg_ParseTuple(args,"f",&blendin))
660         {
661                 m_blendin = blendin;
662         }
663         else {
664                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
665                 return NULL;
666         }
667         
668         Py_INCREF(Py_None);
669         return Py_None;
670 }
671
672 /*     setBlendtime                                                          */
673 char BL_ShapeActionActuator::SetBlendtime_doc[] = 
674 "setBlendtime(blendtime)\n"
675 "\t - blendtime : Allows the script to directly modify the internal timer\n"
676 "\t               used when generating transitions between actions.  This\n"
677 "\t               parameter must be in the range from 0.0 to 1.0.\n";
678
679 PyObject* BL_ShapeActionActuator::PySetBlendtime(PyObject* self, 
680                                                                                                  PyObject* args, 
681                                                                                                    PyObject* kwds) {
682         float blendframe;
683         
684         if (PyArg_ParseTuple(args,"f",&blendframe))
685         {
686                 m_blendframe = blendframe * m_blendin;
687                 if (m_blendframe<0.f)
688                         m_blendframe = 0.f;
689                 if (m_blendframe>m_blendin)
690                         m_blendframe = m_blendin;
691         }
692         else {
693                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
694                 return NULL;
695         }
696         
697         Py_INCREF(Py_None);
698         return Py_None;
699 }
700
701 /*     setPriority                                                           */
702 char BL_ShapeActionActuator::SetPriority_doc[] = 
703 "setPriority(priority)\n"
704 "\t - priority  : Specifies the new priority.  Actuators will lower\n"
705 "\t               priority numbers will override actuators with higher\n"
706 "\t               numbers.\n";
707
708 PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self, 
709                                                                                                 PyObject* args, 
710                                                                                                 PyObject* kwds) {
711         int priority;
712         
713         if (PyArg_ParseTuple(args,"i",&priority))
714         {
715                 m_priority = priority;
716         }
717         else {
718                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
719                 return NULL;
720         }
721         
722         Py_INCREF(Py_None);
723         return Py_None;
724 }
725
726 /*     setFrame                                                              */
727 char BL_ShapeActionActuator::SetFrame_doc[] = 
728 "setFrame(frame)\n"
729 "\t - frame     : Specifies the new current frame for the animation\n";
730
731 PyObject* BL_ShapeActionActuator::PySetFrame(PyObject* self, 
732                                                                                          PyObject* args, 
733                                                                                          PyObject* kwds) {
734         float frame;
735         
736         if (PyArg_ParseTuple(args,"f",&frame))
737         {
738                 m_localtime = frame;
739                 if (m_localtime<m_startframe)
740                         m_localtime=m_startframe;
741                 else if (m_localtime>m_endframe)
742                         m_localtime=m_endframe;
743         }
744         else {
745                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
746                 return NULL;
747         }
748         
749         Py_INCREF(Py_None);
750         return Py_None;
751 }
752
753 /*     setProperty                                                           */
754 char BL_ShapeActionActuator::SetProperty_doc[] = 
755 "setProperty(prop)\n"
756 "\t - prop      : A string specifying the property name to be used in\n"
757 "\t               FromProp playback mode.\n";
758
759 PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self, 
760                                                                                                 PyObject* args, 
761                                                                                                 PyObject* kwds) {
762         char *string;
763         
764         if (PyArg_ParseTuple(args,"s",&string))
765         {
766                 m_propname = string;
767         }
768         else {
769                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
770                 return NULL;
771         }
772         
773         Py_INCREF(Py_None);
774         return Py_None;
775 }
776
777 /* getType */
778 char BL_ShapeActionActuator::GetType_doc[] =
779 "getType()\n"
780 "\tReturns the operation mode of the actuator.\n";
781 PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self) {
782     return Py_BuildValue("h", m_playtype);
783 }
784
785 /* setType */
786 char BL_ShapeActionActuator::SetType_doc[] =
787 "setType(mode)\n"
788 "\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n"
789 "\tSet the operation mode of the actuator.\n";
790 PyObject* BL_ShapeActionActuator::PySetType(PyObject* self,
791                                             PyObject* args,
792                                             PyObject* kwds) {
793         short typeArg;
794                                                                                                              
795     if (!PyArg_ParseTuple(args, "h", &typeArg)) {
796                 PyErr_SetString(PyExc_TypeError, "Invalid arguments");
797         return NULL;
798     }
799
800         switch (typeArg) {
801         case ACT_ACTION_PLAY:
802         case ACT_ACTION_FLIPPER:
803         case ACT_ACTION_LOOP_STOP:
804         case ACT_ACTION_LOOP_END:
805         case ACT_ACTION_FROM_PROP:
806                 m_playtype = typeArg;
807                 break;
808         default:
809                 printf("Invalid type for action actuator: %d\n", typeArg); /* error */
810     }
811         
812     Py_Return;
813 }
814