BGE patch: add state engine support in the logic bricks.
authorBenoit Bolsee <benoit.bolsee@online.be>
Sun, 22 Jun 2008 14:23:57 +0000 (14:23 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Sun, 22 Jun 2008 14:23:57 +0000 (14:23 +0000)
This patch introduces a simple state engine system with the logic bricks. This system features full
backward compatibility, multiple active states, multiple state transitions, automatic disabling of
sensor and actuators, full GUI support and selective display of sensors and actuators.
Note: Python API is available but not documented yet. It will be added asap.

State internals
===============
The state system is object based. The current state mask is stored in the object as a 32 bit value;
each bit set in the mask is an active state. The controllers have a state mask too but only one bit
can be set: a controller belongs to a single state. The game engine will only execute controllers
that belong to active states. Sensors and actuators don't have a state mask but are effectively
attached to states via their links to the controllers. Sensors and actuators can be connected to more
than one state. When a controller becomes inactive because of a state change, its links to sensors
and actuators are temporarily broken (until the state becomes active again). If an actuator gets isolated,
i.e all the links to controllers are broken, it is automatically disabled. If a sensor gets isolated,
the game engine will stop calling it to save CPU. It will also reset the sensor internal state so that
it can react as if the game just started when it gets reconnected to an active controller. For example,
an Always sensor in no pulse mode that is connected to a single state (i.e connected to one or more
controllers of a single state) will generate a pulse each time the state becomes active. This feature is
not available on all sensors, see the notes below.

GUI
===
This system system is fully configurable through the GUI: the object state mask is visible under the
object bar in the controller's colum as an array of buttons just like the 3D view layer mask.
Click on a state bit to only display the controllers of that state. You can select more than one state
with SHIFT-click. The All button sets all the bits so that you can see all the controllers of the object.
The Ini button sets the state mask back to the object default state. You can change the default state
of object by first selecting the desired state mask and storing using the menu under the State button.
If you define a default state mask, it will be loaded into the object state make when you load the blend
file or when you run the game under the blenderplayer. However, when you run the game under Blender,
the current selected state mask will be used as the startup state for the object. This allows you to test
specific state during the game design.

The controller display the state they belong to with a new button in the controller header. When you add
a new controller, it is added by default in the lowest enabled state. You can change the controller state
by clicking on the button and selecting another state. If more than one state is enabled in the object
state mask, controllers are grouped by state for more readibility.

The new Sta button in the sensor and actuator column header allows you to display only the sensors and
actuators that are linked to visible controllers.

A new state actuator is available to modify the state during the game. It defines a bit mask and
the operation to apply on the current object state mask:

Cpy: the bit mask is copied to the object state mask.
Add: the bits that set in the bit mask will be turned on in the object state mask.
Sub: the bits that set in the bit mask will be turned off in the object state mask.
Inv: the bits that set in the bit mask will be inverted in the objecyy state mask.

Notes
=====
- Although states have no name, a simply convention consists in using the name of the first controller
  of the state as the state name. The GUI will support that convention by displaying as a hint the name
  of the first controller of the state when you move the mouse over a state bit of the object state mask
  or of the state actuator bit mask.
- Each object has a state mask and each object can have a state engine but if several objects are
  part of a logical group, it is recommended to put the state engine only in the main object and to
  link the controllers of that object to the sensors and actuators of the different objects.
- When loading an old blend file, the state mask of all objects and controllers are initialized to 1
  so that all the controllers belong to this single state. This ensures backward compatibility with
  existing game.
- When the state actuator is activated at the same time as other actuators, these actuators are
  guaranteed to execute before being eventually disabled due to the state change. This is useful for
  example to send a message or update a property at the time of changing the state.
- Sensors that depend on underlying resource won't reset fully when they are isolated. By the time they
  are acticated again, they will behave as follow:
  * keyboard sensor: keys already pressed won't be detected. The keyboard sensor is only sensitive
    to new key press.
  * collision sensor: objects already colliding won't be detected. Only new collisions are
    detected.
  * near and radar sensor: same as collision sensor.

49 files changed:
projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj
source/blender/blenkernel/intern/sca.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BIF_butspace.h
source/blender/include/BIF_interface.h
source/blender/include/butspace.h
source/blender/makesdna/DNA_actuator_types.h
source/blender/makesdna/DNA_controller_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_sensor_types.h
source/blender/src/buttons_logic.c
source/blender/src/interface.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/Converter/KX_ConvertControllers.cpp
source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
source/gameengine/GameLogic/SCA_AlwaysSensor.h
source/gameengine/GameLogic/SCA_IActuator.cpp
source/gameengine/GameLogic/SCA_IActuator.h
source/gameengine/GameLogic/SCA_IController.cpp
source/gameengine/GameLogic/SCA_IController.h
source/gameengine/GameLogic/SCA_IObject.cpp
source/gameengine/GameLogic/SCA_IObject.h
source/gameengine/GameLogic/SCA_ISensor.cpp
source/gameengine/GameLogic/SCA_ISensor.h
source/gameengine/GameLogic/SCA_JoystickSensor.cpp
source/gameengine/GameLogic/SCA_JoystickSensor.h
source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
source/gameengine/GameLogic/SCA_KeyboardSensor.h
source/gameengine/GameLogic/SCA_LogicManager.cpp
source/gameengine/GameLogic/SCA_MouseSensor.cpp
source/gameengine/GameLogic/SCA_MouseSensor.h
source/gameengine/GameLogic/SCA_PropertySensor.cpp
source/gameengine/GameLogic/SCA_PropertySensor.h
source/gameengine/GameLogic/SCA_RandomSensor.cpp
source/gameengine/GameLogic/SCA_RandomSensor.h
source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
source/gameengine/Ketsji/KX_MouseFocusSensor.h
source/gameengine/Ketsji/KX_RadarSensor.cpp
source/gameengine/Ketsji/KX_RaySensor.cpp
source/gameengine/Ketsji/KX_RaySensor.h
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_StateActuator.cpp [new file with mode: 0644]
source/gameengine/Ketsji/KX_StateActuator.h [new file with mode: 0644]
source/gameengine/Ketsji/KX_TouchSensor.cpp
source/gameengine/Ketsji/KX_TouchSensor.h

index c8173750bdc15687e5b4fba75dbf47c300ddf655..af0ba74497a8829c1f9fc41dd6e40eea2f98d1cb 100644 (file)
                                <File
                                        RelativePath="..\..\..\source\gameengine\Ketsji\KX_SoundActuator.cpp">
                                </File>
+                               <File
+                                       RelativePath="..\..\..\source\gameengine\Ketsji\KX_StateActuator.cpp">
+                               </File>
                                <File
                                        RelativePath="..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.cpp">
                                </File>
                                <File
                                        RelativePath="..\..\..\source\gameengine\Ketsji\KX_SoundActuator.h">
                                </File>
+                               <File
+                                       RelativePath="..\..\..\source\gameengine\Ketsji\KX_StateActuator.h">
+                               </File>
                                <File
                                        RelativePath="..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.h">
                                </File>
index 92544f1972130631fa2f34ef6e2a88924d3825aa..16ca5d7542db42169204d9b9a537e333c3a03b66 100644 (file)
@@ -465,6 +465,9 @@ void init_actuator(bActuator *act)
     case ACT_PARENT:
         act->data = MEM_callocN(sizeof( bParentActuator ), "parent act");
         break;
+       case ACT_STATE:
+        act->data = MEM_callocN(sizeof( bStateActuator ), "state act");
+        break;
        default:
                ; /* this is very severe... I cannot make any memory for this        */
                /* logic brick...                                                    */
index fa7cbb06139a0d1d186317fd7b991e2343f1a83e..9cfce5e34fa02a0d6298fa6fa79eeeca004b93d6 100644 (file)
@@ -3011,6 +3011,9 @@ static void lib_link_object(FileData *fd, Main *main)
                                        bParentActuator *parenta = act->data; 
                                        parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
                                }
+                               else if(act->type==ACT_STATE) {
+                                       /* bStateActuator *statea = act->data; */
+                               }
                                act= act->next;
                        }
 
@@ -3307,11 +3310,19 @@ static void direct_link_object(FileData *fd, Object *ob)
        direct_link_constraints(fd, &ob->constraints);
 
        link_glob_list(fd, &ob->controllers);
+       if (ob->init_state) {
+               /* if a known first state is specified, set it so that the game will start ok */
+               ob->state = ob->init_state;
+       } else if (!ob->state) {
+               ob->state = 1;
+       }
        cont= ob->controllers.first;
        while(cont) {
                cont->data= newdataadr(fd, cont->data);
                cont->links= newdataadr(fd, cont->links);
                test_pointer_array(fd, (void **)&cont->links);
+               if (cont->state_mask == 0)
+                       cont->state_mask = 1;
                cont= cont->next;
        }
 
@@ -7635,6 +7646,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                }
        }
 
+
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
 
index 2595b95bbf0e2fd9b62e28ab34e1c77e6dfd11b0..9f28e13ff7b9d7991f085accc015dc7e76e91f7e 100644 (file)
@@ -715,6 +715,9 @@ static void write_actuators(WriteData *wd, ListBase *lb)
                case ACT_PARENT:
                        writestruct(wd, DATA, "bParentActuator", 1, act->data);
                        break;
+               case ACT_STATE:
+                       writestruct(wd, DATA, "bStateActuator", 1, act->data);
+                       break;
                default:
                        ; /* error: don't know how to write this file */
                }
index cbbd8013c822fac243f475188b6d7f40438cb045..f0b37814947a084f0b7772ff002ded8cdddb35fb 100644 (file)
@@ -99,6 +99,8 @@ extern void validate_editbonebutton_cb(void *bonev, void *namev);
 #define BUTS_ACT_SEL           64
 #define BUTS_ACT_ACT           128
 #define BUTS_ACT_LINK          256
+#define BUTS_SENS_STATE                512
+#define BUTS_ACT_STATE         1024
 
 
 /* buttons grid */
index fbd4e4ecd91b642532bf5e8c32b1bc67ef45637b..3da4466d4d36d056a7ba828cc0a0db7f86bd6e61 100644 (file)
@@ -185,6 +185,7 @@ void uiDrawBlock(struct uiBlock *block);
 void uiGetMouse(int win, short *adr);
 void uiComposeLinks(uiBlock *block);
 void uiSetButLock(int val, char *lockstr);
+uiBut *uiFindInlink(uiBlock *block, void *poin);
 void uiClearButLock(void);
 int uiDoBlocks(struct ListBase *lb, int event, int movemouse_quit);
 void uiSetCurFont(uiBlock *block, int index);
index 7571d64be91a1fe798d0a86e0b639b0c87dd0283..c0542e3f34c17ca11a4bffaa1b89eabdf3258dd6 100644 (file)
@@ -52,6 +52,8 @@ struct Image;
 #define BUTS_ACT_SEL           64
 #define BUTS_ACT_ACT           128
 #define BUTS_ACT_LINK          256
+#define BUTS_SENS_STATE                512
+#define BUTS_ACT_STATE         1024
 
 /* internal */
 
@@ -583,6 +585,8 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 #define B_SETACTOR             2715
 #define B_SETMAINACTOR         2716
 #define B_SETDYNA              2717
+#define B_SET_STATE_BIT        2718
+#define B_INIT_STATE_BIT       2719
 
 /* *********************** */
 #define B_FPAINTBUTS           2900
index a326f5b01d60bac3752e2c8f61eec50bedbfe851..417ba540e2cbf3812c75d0a9636796639c750294 100644 (file)
@@ -208,6 +208,11 @@ typedef struct bParentActuator {
        struct Object *ob;
 } bParentActuator;
 
+typedef struct bStateActuator {
+       int type;                       /* 0=Set, 1=Add, 2=Rem, 3=Chg */
+       unsigned int mask;      /* the bits to change */
+} bStateActuator;
+
 typedef struct bActuator {
        struct bActuator *next, *prev, *mynew;
        short type;
@@ -279,11 +284,14 @@ typedef struct FreeCamera {
 #define ACT_2DFILTER   19
 #define ACT_PARENT      20
 #define ACT_SHAPEACTION 21
+#define ACT_STATE              22
 
 /* actuator flag */
 #define ACT_SHOW               1
 #define ACT_DEL                        2
 #define ACT_NEW                        4
+#define ACT_LINKED             8       
+#define ACT_VISIBLE            16      
 
 /* link codes */
 #define LINK_SENSOR            0
index 95c9b0d0cf7b0f72fed212d014bdd2048b74321a..cc9215e7d14a42fcc7de3c60c68380c9e7dd8c84 100644 (file)
@@ -57,7 +57,7 @@ typedef struct bController {
 
        struct bSensor **slinks;
        short val, valo;
-       int pad5;
+       unsigned int state_mask;
        
 } bController;
 
@@ -71,6 +71,7 @@ typedef struct bController {
 #define CONT_SHOW              1
 #define CONT_DEL               2
 #define CONT_NEW               4
+#define CONT_MASK              8
 
 #endif
 
index 83168248b9a096f01c330783f013a963b3b0e259..c4e8cb4925b83aeff9bace19c457583f853a626e 100644 (file)
@@ -216,7 +216,9 @@ typedef struct Object {
 
        struct DerivedMesh *derivedDeform, *derivedFinal;
        int lastDataMask;                       /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
-       int pad;
+       unsigned int state;                     /* bit masks of game controllers that are active */
+       unsigned int init_state;        /* bit masks of initial state as recorded by the users */
+       int pad2;
 
 /*#ifdef WITH_VERSE*/
        void *vnode;                    /* pointer at object VerseNode */
@@ -440,6 +442,8 @@ extern Object workob;
 #define OB_ADDCONT             512
 #define OB_ADDACT              1024
 #define OB_SHOWCONT            2048
+#define OB_SETSTBIT            4096
+#define OB_INITSTBIT   8192
 
 /* ob->restrictflag */
 #define OB_RESTRICT_VIEW       1
index 90e2b8f9f413475d914d94399678e2bc223a16a1..3fd57a8534907571f5daaae3ccb8ef0243407d27 100644 (file)
@@ -202,6 +202,7 @@ typedef struct bJoystickSensor {
 #define SENS_DEL               2
 #define SENS_NEW               4
 #define SENS_NOT               8
+#define SENS_VISIBLE   16
 
 /* sensor->pulse */
 #define SENS_PULSE_CONT        0
index b6877b2e2b766fd3e060926563476751069e233e..c4fc17bc4d0d58aef0d953261ddedcbe3cd40cfd 100644 (file)
@@ -88,6 +88,7 @@
 #include "mydevice.h"
 #include "nla.h"       /* For __NLA : Important, do not remove */
 #include "butspace.h" // own module
+#include "interface.h"
 
 /* internals */
 void buttons_enji(uiBlock *, Object *);
@@ -228,7 +229,7 @@ static void sca_move_sensor(void *datav, void *data2_unused)
        bSensor *sens_to_delete= datav;
        int val;
        Base *base;
-       bSensor *sens;
+       bSensor *sens, *tmp;
        
        val= pupmenu("Move up%x1|Move down %x2");
        
@@ -245,12 +246,24 @@ static void sca_move_sensor(void *datav, void *data2_unused)
                        
                        if(sens) {
                                if( val==1 && sens->prev) {
-                                       BLI_remlink(&base->object->sensors, sens);
-                                       BLI_insertlinkbefore(&base->object->sensors, sens->prev, sens);
+                                       for (tmp=sens->prev; tmp; tmp=tmp->prev) {
+                                               if (tmp->flag & SENS_VISIBLE)
+                                                       break;
+                                       }
+                                       if (tmp) {
+                                               BLI_remlink(&base->object->sensors, sens);
+                                               BLI_insertlinkbefore(&base->object->sensors, tmp, sens);
+                                       }
                                }
                                else if( val==2 && sens->next) {
-                                       BLI_remlink(&base->object->sensors, sens);
-                                       BLI_insertlink(&base->object->sensors, sens->next, sens);
+                                       for (tmp=sens->next; tmp; tmp=tmp->next) {
+                                               if (tmp->flag & SENS_VISIBLE)
+                                                       break;
+                                       }
+                                       if (tmp) {
+                                               BLI_remlink(&base->object->sensors, sens);
+                                               BLI_insertlink(&base->object->sensors, tmp, sens);
+                                       }
                                }
                                BIF_undo_push("Move sensor");
                                allqueue(REDRAWBUTSLOGIC, 0);
@@ -267,7 +280,7 @@ static void sca_move_controller(void *datav, void *data2_unused)
        bController *controller_to_del= datav;
        int val;
        Base *base;
-       bController *cont;
+       bController *cont, *tmp;
        
        val= pupmenu("Move up%x1|Move down %x2");
        
@@ -284,12 +297,27 @@ static void sca_move_controller(void *datav, void *data2_unused)
                        
                        if(cont) {
                                if( val==1 && cont->prev) {
-                                       BLI_remlink(&base->object->controllers, cont);
-                                       BLI_insertlinkbefore(&base->object->controllers, cont->prev, cont);
+                                       /* locate the controller that has the same state mask but is earlier in the list */
+                                       tmp = cont->prev;
+                                       while(tmp) {
+                                               if(tmp->state_mask & cont->state_mask) 
+                                                       break;
+                                               tmp = tmp->prev;
+                                       }
+                                       if (tmp) {
+                                               BLI_remlink(&base->object->controllers, cont);
+                                               BLI_insertlinkbefore(&base->object->controllers, tmp, cont);
+                                       }
                                }
                                else if( val==2 && cont->next) {
+                                       tmp = cont->next;
+                                       while(tmp) {
+                                               if(tmp->state_mask & cont->state_mask) 
+                                                       break;
+                                               tmp = tmp->next;
+                                       }
                                        BLI_remlink(&base->object->controllers, cont);
-                                       BLI_insertlink(&base->object->controllers, cont->next, cont);
+                                       BLI_insertlink(&base->object->controllers, tmp, cont);
                                }
                                BIF_undo_push("Move controller");
                                allqueue(REDRAWBUTSLOGIC, 0);
@@ -306,7 +334,7 @@ static void sca_move_actuator(void *datav, void *data2_unused)
        bActuator *actuator_to_move= datav;
        int val;
        Base *base;
-       bActuator *act;
+       bActuator *act, *tmp;
        
        val= pupmenu("Move up%x1|Move down %x2");
        
@@ -323,12 +351,25 @@ static void sca_move_actuator(void *datav, void *data2_unused)
                        
                        if(act) {
                                if( val==1 && act->prev) {
-                                       BLI_remlink(&base->object->actuators, act);
-                                       BLI_insertlinkbefore(&base->object->actuators, act->prev, act);
+                                       /* locate the first visible actuators before this one */
+                                       for (tmp = act->prev; tmp; tmp=tmp->prev) {
+                                               if (tmp->flag & ACT_VISIBLE)
+                                                       break;
+                                       }
+                                       if (tmp) {
+                                               BLI_remlink(&base->object->actuators, act);
+                                               BLI_insertlinkbefore(&base->object->actuators, tmp, act);
+                                       }
                                }
                                else if( val==2 && act->next) {
-                                       BLI_remlink(&base->object->actuators, act);
-                                       BLI_insertlink(&base->object->actuators, act->next, act);
+                                       for (tmp=act->next; tmp; tmp=tmp->next) {
+                                               if (tmp->flag & ACT_VISIBLE)
+                                                       break;
+                                       }
+                                       if (tmp) {
+                                               BLI_remlink(&base->object->actuators, act);
+                                               BLI_insertlink(&base->object->actuators, tmp, act);
+                                       }
                                }
                                BIF_undo_push("Move actuator");
                                allqueue(REDRAWBUTSLOGIC, 0);
@@ -348,7 +389,7 @@ void do_logic_buts(unsigned short event)
        bActuator *act;
        Base *base;
        Object *ob;
-       int didit;
+       int didit, bit;
        
        ob= OBACT;
        if(ob==0) return;
@@ -462,6 +503,18 @@ void do_logic_buts(unsigned short event)
                                make_unique_prop_names(cont->name);
                                base->object->scaflag |= OB_SHOWCONT;
                                BLI_addtail(&(base->object->controllers), cont);
+                               /* set the controller state mask from the current object state.
+                                  A controller is always in a single state, so select the lowest bit set
+                                  from the object state */
+                               for (bit=0; bit<32; bit++) {
+                                       if (base->object->state & (1<<bit))
+                                               break;
+                               }
+                               cont->state_mask = (1<<bit);
+                               if (cont->state_mask == 0) {
+                                       /* shouldn't happen, object state is never 0 */
+                                       cont->state_mask = 1;
+                               }
                        }
                        base= base->next;
                }
@@ -469,6 +522,32 @@ void do_logic_buts(unsigned short event)
                allqueue(REDRAWBUTSLOGIC, 0);
                break;
 
+       case B_SET_STATE_BIT:
+               base= FIRSTBASE;
+               while(base) {
+                       if(base->object->scaflag & OB_SETSTBIT) {
+                               base->object->scaflag &= ~OB_SETSTBIT;
+                               base->object->state = 0x3FFFFFFF;
+                       }
+                       base= base->next;
+               }
+               allqueue(REDRAWBUTSLOGIC, 0);
+               break;
+
+       case B_INIT_STATE_BIT:
+               base= FIRSTBASE;
+               while(base) {
+                       if(base->object->scaflag & OB_INITSTBIT) {
+                               base->object->scaflag &= ~OB_INITSTBIT;
+                               base->object->state = base->object->init_state;
+                               if (!base->object->state)
+                                       base->object->state = 1;
+                       }
+                       base= base->next;
+               }
+               allqueue(REDRAWBUTSLOGIC, 0);
+               break;
+
        case B_CHANGE_CONT:
                base= FIRSTBASE;
                while(base) {
@@ -505,7 +584,7 @@ void do_logic_buts(unsigned short event)
                BIF_undo_push("Delete controller");
                allqueue(REDRAWBUTSLOGIC, 0);
                break;
-       
+
        case B_ADD_ACT:
                base= FIRSTBASE;
                while(base) {
@@ -717,6 +796,8 @@ static char *actuator_name(int type)
                return "2D Filter";
        case ACT_PARENT:
                return "Parent";
+       case ACT_STATE:
+               return "State";
        }
        return "unknown";
 }
@@ -732,21 +813,21 @@ static char *actuator_pup(Object *owner)
                return "Actuators  %t|Action %x15|Motion %x0|Constraint %x9|Ipo %x1"
                        "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10"
                        "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17"
-                       "|Visibility %x18|2D Filter %x19|Parent %x20";
+                       "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22";
                break;
 
        case OB_MESH:
                return "Actuators  %t|Shape Action %x21|Motion %x0|Constraint %x9|Ipo %x1"
                        "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10"
                        "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17"
-                       "|Visibility %x18|2D Filter %x19|Parent %x20";
+                       "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22";
                break;
 
        default:
                return "Actuators  %t|Motion %x0|Constraint %x9|Ipo %x1"
                        "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10"
                        "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17"
-                       "|Visibility %x18|2D Filter %x19|Parent %x20";
+                       "|Visibility %x18|2D Filter %x19|Parent %x20|State %x22";
        }
 }
 
@@ -815,7 +896,8 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag)
                if(scavisflag & BUTS_ACT_ACT) OBACT->scavisflag |= OB_VIS_ACT;
        }
        
-       if(scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK)) {
+       /* BUTS_XXX_STATE are similar to BUTS_XXX_LINK for selecting the object */
+       if(scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK|BUTS_SENS_STATE|BUTS_ACT_STATE)) {
                doit= 1;
                while(doit) {
                        doit= 0;
@@ -824,7 +906,7 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag)
                        while(ob) {
                        
                                /* 1st case: select sensor when controller selected */
-                               if((scavisflag & BUTS_SENS_LINK) && (ob->scavisflag & OB_VIS_SENS)==0) {
+                               if((scavisflag & (BUTS_SENS_LINK|BUTS_SENS_STATE)) && (ob->scavisflag & OB_VIS_SENS)==0) {
                                        sens= ob->sensors.first;
                                        while(sens) {
                                                for(a=0; a<sens->totlinks; a++) {
@@ -879,7 +961,7 @@ static ID **get_selected_and_linked_obs(short *count, short scavisflag)
                                }
                                
                                /* 4th case: select actuator when controller selected */
-                               if( (scavisflag & BUTS_ACT_LINK)  && (ob->scavisflag & OB_VIS_CONT)) {
+                               if( (scavisflag & (BUTS_ACT_LINK|BUTS_ACT_STATE))  && (ob->scavisflag & OB_VIS_CONT)) {
                                        cont= ob->controllers.first;
                                        while(cont) {
                                                for(a=0; a<cont->totlinks; a++) {
@@ -1458,6 +1540,7 @@ static int get_col_actuator(int type)
        case ACT_GAME:                  return TH_BUT_SETTING2;
        case ACT_VISIBILITY:            return TH_BUT_NUM;
        case ACT_CONSTRAINT:            return TH_BUT_ACTION;
+       case ACT_STATE:                 return TH_BUT_SETTING2;
        default:                                return TH_BUT_NEUTRAL;
        }
 }
@@ -1468,7 +1551,23 @@ static void set_col_actuator(int item, int medium)
        
 }
 
-static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, short yco, short width)
+char *get_state_name(Object *ob, short bit)
+{
+       bController *cont;
+       unsigned int mask;
+
+       mask = (1<<bit);
+       cont = ob->controllers.first;
+       while (cont) {
+               if (cont->state_mask & mask) {
+                       return cont->name;
+               }
+               cont = cont->next;
+       }
+       return (char*)"";
+}
+
+static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, short xco, short yco, short width)
 {
        bSoundActuator      *sa      = NULL;
        bCDActuator                     *cda     = NULL;
@@ -1487,11 +1586,12 @@ static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, sho
        bVisibilityActuator *visAct  = NULL;
        bTwoDFilterActuator     *tdfa    = NULL;
        bParentActuator     *parAct  = NULL;
+       bStateActuator          *staAct  = NULL;
        
        float *fp;
        short ysize = 0, wval;
-       char *str;
-       int myline;
+       char *str, name[32];
+       int myline, stbit;
 
        /* yco is at the top of the rect, draw downwards */
        uiBlockSetEmboss(block, UI_EMBOSSM);
@@ -2022,6 +2122,37 @@ static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, sho
 
                break;
                
+       case ACT_STATE:
+               ysize = 34;
+
+               glRects(xco, yco-ysize, xco+width, yco);
+               uiEmboss((float)xco,
+                        (float)yco-ysize, (float)xco+width, (float)yco, 1);
+               
+               staAct = act->data;
+
+               str= "Operation %t|Cpy %x0|Add %x1|Sub %x2|Inv %x3";
+
+               uiDefButI(block, MENU, B_REDR, str,
+                         xco + 10, yco - 24, 65, 19, &staAct->type,
+                         0.0, 0.0, 0, 0,
+                         "Select the bit operation on object state mask");
+
+               for (wval=0; wval<15; wval+=5) {
+                       uiBlockBeginAlign(block);
+                       for (stbit=0; stbit<5; stbit++) {
+                               uiDefButBitI(block, TOG, (1<<(stbit+wval)), 0, "",      (short)(xco+85+12*stbit+13*wval), yco-17, 12, 12, (int *)&(staAct->mask), 0, 0, 0, 0, get_state_name(ob, (short)(wval+stbit)));
+                       }
+                       for (stbit=0; stbit<5; stbit++) {
+                               uiDefButBitI(block, TOG, (1<<(stbit+wval+15)), 0, "",   (short)(xco+85+12*stbit+13*wval), yco-29, 12, 12, (int *)&(staAct->mask), 0, 0, 0, 0, get_state_name(ob, (short)(wval+stbit+15)));
+                       }
+               }
+               uiBlockEndAlign(block);
+
+               yco-= ysize;
+
+               break;
+
        case ACT_RANDOM:
                ysize  = 69;
 
@@ -2596,6 +2727,120 @@ void buttons_bullet(uiBlock *block, Object *ob)
        uiBlockEndAlign(block);
 }
 
+static void check_object_state(void *arg1_but, void *arg2_mask)
+{
+       unsigned int *cont_mask = arg2_mask;
+       uiBut *but = arg1_but;
+
+       if (*cont_mask == 0 || !(G.qual & LR_SHIFTKEY))
+               *cont_mask = (1<<but->retval);
+       but->retval = B_REDR;
+}
+
+static void check_controller_state_mask(void *arg1_but, void *arg2_mask)
+{
+       unsigned int *cont_mask = arg2_mask;
+       uiBut *but = arg1_but;
+       
+       /* a controller is always in a single state */
+       *cont_mask = (1<<but->retval);
+       but->retval = B_REDR;
+}
+
+static int first_bit(unsigned int mask)
+{
+       int bit;
+
+       for (bit=0; bit<32; bit++) {
+               if (mask & (1<<bit))
+                       return bit;
+       }
+       return -1;
+}
+
+static uiBlock *controller_state_mask_menu(void *arg_cont)
+{
+       uiBlock *block;
+       uiBut *but;
+       bController *cont = arg_cont;
+       int mask;
+
+       short yco = 12, xco = 0, stbit, offset;
+
+       block= uiNewBlock(&curarea->uiblocks, "Controller state mask", UI_EMBOSS, UI_HELV, curarea->win);
+
+       /* use this for a fake extra empy space around the buttons */
+       uiDefBut(block, LABEL, 0, "",                   -5, -5, 200, 34, NULL, 0, 0, 0, 0, "");
+       
+       for (offset=0; offset<15; offset+=5) {
+               uiBlockBeginAlign(block);
+               for (stbit=0; stbit<5; stbit++) {
+                       but = uiDefButBitI(block, TOG, (1<<(stbit+offset)), (stbit+offset), "", (short)(xco+12*stbit+13*offset), yco, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
+                       uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask));
+               }
+               for (stbit=0; stbit<5; stbit++) {
+                       but = uiDefButBitI(block, TOG, (1<<(stbit+offset+15)), (stbit+offset+15), "",   (short)(xco+12*stbit+13*offset), yco-12, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
+                       uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask));
+               }
+       }
+       uiBlockEndAlign(block);
+
+       uiBlockSetDirection(block, UI_TOP);
+
+       return block;
+}
+
+static void do_object_state_menu(void *arg, int event)
+{      
+       Object *ob = arg;
+
+       switch (event) {
+       case 0:
+               ob->state = 0x3FFFFFFF;
+               break;
+       case 1:
+               ob->state = ob->init_state;
+               if (!ob->state)
+                       ob->state = 1;
+               break;
+       case 2:
+               ob->init_state = ob->state;
+               break;
+       }
+       allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+static uiBlock *object_state_mask_menu(void *arg_obj)
+{
+       uiBlock *block;
+       uiBut *but;
+       short xco = 0;
+
+       block= uiNewBlock(&curarea->uiblocks, "obstatemenu", UI_EMBOSSP, UI_HELV, curarea->win);
+       uiBlockSetButmFunc(block, do_object_state_menu, arg_obj);
+       
+       uiDefBut(block, BUTM, 1, "Set all bits",                0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+       uiDefBut(block, BUTM, 1, "Recall init state",   0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+       uiDefBut(block, SEPR, 0, "",                                    0, (short)(xco-=6),      160, 6,  NULL, 0.0, 0.0, 0, 0, "");
+       uiDefBut(block, BUTM, 1, "Store init state",    0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+       uiBlockSetDirection(block, UI_TOP);
+       return block;
+}
+
+static int is_sensor_linked(uiBlock *block, bSensor *sens)
+{
+       bController *cont;
+       int i, count;
+
+       for (count=0, i=0; i<sens->totlinks; i++) {
+               cont = sens->links[i];
+               if (uiFindInlink(block, cont) != NULL)
+                       return 1;
+       }
+       return 0;
+}
+
 /* never used, see CVS 1.134 for the code */
 /*  static FreeCamera *new_freecamera(void) */
 
@@ -2614,7 +2859,7 @@ void logic_buts(void)
        uiBlock *block;
        uiBut *but;
        World *wrld;
-       int a;
+       int a, iact, stbit, offset;
        short xco, yco, count, width, ycoo;
        char *pupstr, name[32];
 
@@ -2686,158 +2931,241 @@ void logic_buts(void)
        uiClearButLock();
 
        idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
-       
+
+       /* clean ACT_LINKED and ACT_VISIBLE of all potentially visible actuators so that 
+          we can determine which is actually linked/visible */
+       for(a=0; a<count; a++) {
+               ob= (Object *)idar[a];
+               act= ob->actuators.first;
+               while(act) {
+                       act->flag &= ~(ACT_LINKED|ACT_VISIBLE);
+                       act = act->next;
+               }
+               /* same for sensors */
+               sens= ob->sensors.first;
+               while(sens) {
+                       sens->flag &= ~(SENS_VISIBLE);
+                       sens = sens->next;
+               }
+       }
+               
+       /* start with the controller because we need to know which one is visible */
        /* ******************************* */
-       xco= 375; yco= 170; width= 230;
+       xco= 695; yco= 170; width= 275;
 
        uiBlockSetEmboss(block, UI_EMBOSSP);
-       uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 80, 19, "");
+       uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, "");
        uiBlockSetEmboss(block, UI_EMBOSS);
        
        uiBlockBeginAlign(block);
-       uiDefButBitS(block, TOG, BUTS_SENS_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
-       uiDefButBitS(block, TOG, BUTS_SENS_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
-       uiDefButBitS(block, TOG, BUTS_SENS_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+       uiDefButBitS(block, TOG, BUTS_CONT_SEL,  B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+       uiDefButBitS(block, TOG, BUTS_CONT_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+       uiDefButBitS(block, TOG, BUTS_CONT_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Sensor/Actuator");
        uiBlockEndAlign(block);
        
+       ob= OBACT;
+       
        for(a=0; a<count; a++) {
                ob= (Object *)idar[a];
                uiClearButLock();
                uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
-               
-               if( (ob->scavisflag & OB_VIS_SENS) == 0) continue;
-               
+               if( (ob->scavisflag & OB_VIS_CONT) == 0) continue;
+
                /* presume it is only objects for now */
                uiBlockSetEmboss(block, UI_EMBOSS);
                uiBlockBeginAlign(block);
-               if(ob->sensors.first) uiSetCurFont(block, UI_HELVB);
-               uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide sensors");
-               if(ob->sensors.first) uiSetCurFont(block, UI_HELV);
-               uiDefButBitS(block, TOG, OB_ADDSENS, B_ADD_SENS, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Sensor");
+               if(ob->controllers.first) uiSetCurFont(block, UI_HELVB);
+               uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 0, 0, 0, "Active Object name");
+               if(ob->controllers.first) uiSetCurFont(block, UI_HELV);
+               uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller");
                uiBlockEndAlign(block);
-               yco-=20;
+               yco-=17;
                
-               if(ob->scaflag & OB_SHOWSENS) {
-                       
-                       sens= ob->sensors.first;
-                       while(sens) {
-                               uiBlockSetEmboss(block, UI_EMBOSSM);
-                               uiDefIconButBitS(block, TOG, SENS_DEL, B_DEL_SENS, ICON_X,      xco, yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Delete Sensor");
-                               uiDefIconButBitS(block, ICONTOG, SENS_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Sensor settings");
+               /* mark all actuators linked to these controllers */
+               /* note that some of these actuators could be from objects that are not in the display list.
+                  It's ok because those actuators will not be displayed here */
+               cont= ob->controllers.first;
+               while(cont) {
+                       for (iact=0; iact<cont->totlinks; iact++) {
+                               act = cont->links[iact];
+                               act->flag |= ACT_LINKED;
+                       }
+                       cont = cont->next;
+               }
 
-                               ycoo= yco;
-                               if(sens->flag & SENS_SHOW)
-                               {
-                                       uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(),     (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type");
-                                       but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name");
-                                       uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0);
+               if(ob->scaflag & OB_SHOWCONT) {
 
-                                       sens->otype= sens->type;
-                                       yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name);
-                                       if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+                       /* first show the state */
+                       uiBlockSetEmboss(block, UI_EMBOSSP);
+                       uiDefBlockBut(block, object_state_mask_menu, ob, "State", (short)(xco-10), (short)(yco-10), 40, 19, "Object state menu: store and retrieve initial state");
+                       uiBlockSetEmboss(block, UI_EMBOSS);
+                       if (!ob->state)
+                               ob->state = 1;
+                       for (offset=0; offset<15; offset+=5) {
+                               uiBlockBeginAlign(block);
+                               for (stbit=0; stbit<5; stbit++) {
+                                       but = uiDefButBitI(block, TOG, 1<<(stbit+offset), stbit+offset, "",     (short)(xco+35+12*stbit+13*offset), yco, 12, 12, (int *)&(ob->state), 0, 0, 0, 0, get_state_name(ob, (short)(stbit+offset)));
+                                       uiButSetFunc(but, check_object_state, but, &(ob->state));
                                }
-                               else {
-                                       set_col_sensor(sens->type, 1);
-                                       glRecti(xco+22, yco, xco+width-22,yco+19);
-                                       but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, "");
-                                       uiButSetFunc(but, sca_move_sensor, sens, NULL);
-                                       but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, "");
-                                       uiButSetFunc(but, sca_move_sensor, sens, NULL);
+                               for (stbit=0; stbit<5; stbit++) {
+                                       but = uiDefButBitI(block, TOG, 1<<(stbit+offset+15), stbit+offset+15, "",       (short)(xco+35+12*stbit+13*offset), yco-12, 12, 12, (int *)&(ob->state), 0, 0, 0, 0, get_state_name(ob, (short)(stbit+offset+15)));
+                                       uiButSetFunc(but, check_object_state, but, &(ob->state));
                                }
+                       }
+                       uiBlockBeginAlign(block);
+                       uiDefButBitS(block, TOG, OB_SETSTBIT, B_SET_STATE_BIT, "All",(short)(xco+235), yco-10, 25, 19, &ob->scaflag, 0, 0, 0, 0, "Set all state bits");
+                       uiDefButBitS(block, TOG, OB_INITSTBIT, B_INIT_STATE_BIT, "Ini",(short)(xco+260), yco-10, 25, 19, &ob->scaflag, 0, 0, 0, 0, "Set the initial state");
+                       uiBlockEndAlign(block);
 
-                               but= uiDefIconBut(block, LINK, 0, ICON_LINK,    (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
-                               uiSetButLink(but, NULL, (void ***)&(sens->links), &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
-
-                               yco-=20;
+                       yco-=35;
+               
+                       /* display only the controllers that match the current state */
+                       offset = 0;
+                       for (stbit=0; stbit<32; stbit++) {
+                               if (!(ob->state & (1<<stbit)))
+                                       continue;
+                               /* add a separation between controllers of different states */
+                               if (offset) {
+                                       offset = 0;
+                                       yco -= 6;
+                               }
+                               cont= ob->controllers.first;
+                               while(cont) {
+                                       if (cont->state_mask & (1<<stbit)) {
+                                               /* this controller is visible, mark all its actuator */
+                                               for (iact=0; iact<cont->totlinks; iact++) {
+                                                       act = cont->links[iact];
+                                                       act->flag |= ACT_VISIBLE;
+                                               }
+                                               uiBlockSetEmboss(block, UI_EMBOSSM);
+                                               uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X,      xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller");
+                                               uiDefIconButBitS(block, ICONTOG, CONT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Controller settings");
+                                               uiBlockSetEmboss(block, UI_EMBOSSP);
+                                               sprintf(name, "%d", first_bit(cont->state_mask)+1);
+                                               uiDefBlockBut(block, controller_state_mask_menu, cont, name, (short)(xco+width-44), yco, 22, 19, "Set controller state mask");
+                                               uiBlockSetEmboss(block, UI_EMBOSSM);
+                               
+                                               if(cont->flag & CONT_SHOW) {
+                                                       cont->otype= cont->type;
+                                                       uiDefButS(block, MENU, B_CHANGE_CONT, controller_pup(),(short)(xco+22), yco, 100, 19, &cont->type, 0, 0, 0, 0, "Controller type");
+                                                       but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-166), 19, cont->name, 0, 31, 0, 0, "Controller name");
+                                                       uiButSetFunc(but, make_unique_prop_names_cb, cont->name, (void*) 0);
+                               
+                                                       ycoo= yco;
+                                                       yco= draw_controllerbuttons(cont, block, xco, yco, width);
+                                                       if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+                                               }
+                                               else {
+                                                       cpack(0x999999);
+                                                       glRecti(xco+22, yco, xco+width-22,yco+19);
+                                                       but= uiDefBut(block, LABEL, 0, controller_name(cont->type), (short)(xco+22), yco, 100, 19, cont, 0, 0, 0, 0, "Controller type");
+                                                       uiButSetFunc(but, sca_move_controller, cont, NULL);
+                                                       but= uiDefBut(block, LABEL, 0, cont->name,(short)(xco+122), yco,(short)(width-166), 19, cont, 0, 0, 0, 0, "Controller name");
+                                                       uiButSetFunc(but, sca_move_controller, cont, NULL);
+                                                       ycoo= yco;
+                                               }
+                               
+                                               but= uiDefIconBut(block, LINK, 0, ICON_LINK,    (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
+                                               uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
+                               
+                                               uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, cont, LINK_CONTROLLER, 0, 0, 0, "");
+                                               /* offset is >0 if at least one controller was displayed */
+                                               offset++;
+                                               yco-=20;
+                                       }
+                                       cont= cont->next;
+                               }
 
-                               sens= sens->next;
                        }
                        yco-= 6;
                }
        }
-
+       
        /* ******************************* */
-       xco= 675; yco= 170; width= 230;
+       xco= 375; yco= 170; width= 250;
 
        uiBlockSetEmboss(block, UI_EMBOSSP);
-       uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, "");
+       uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 70, 19, "");
        uiBlockSetEmboss(block, UI_EMBOSS);
        
        uiBlockBeginAlign(block);
-       uiDefButBitS(block, TOG, BUTS_CONT_SEL,  B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
-       uiDefButBitS(block, TOG, BUTS_CONT_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
-       uiDefButBitS(block, TOG, BUTS_CONT_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Sensor/Actuator");
+       uiDefButBitS(block, TOG, BUTS_SENS_SEL, B_REDR, "Sel", xco+80, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+       uiDefButBitS(block, TOG, BUTS_SENS_ACT, B_REDR, "Act", xco+80+(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+       uiDefButBitS(block, TOG, BUTS_SENS_LINK, B_REDR, "Link", xco+80+2*(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+       uiDefButBitS(block, TOG, BUTS_SENS_STATE, B_REDR, "Sta", xco+80+3*(width-70)/4, yco+35, (width-70)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show only sensors connected to active states");
        uiBlockEndAlign(block);
        
-       ob= OBACT;
-       
        for(a=0; a<count; a++) {
                ob= (Object *)idar[a];
                uiClearButLock();
                uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
-               if( (ob->scavisflag & OB_VIS_CONT) == 0) continue;
-
+               
+               if( (ob->scavisflag & OB_VIS_SENS) == 0) continue;
+               
                /* presume it is only objects for now */
                uiBlockSetEmboss(block, UI_EMBOSS);
                uiBlockBeginAlign(block);
-               if(ob->controllers.first) uiSetCurFont(block, UI_HELVB);
-               uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 0, 0, 0, "Active Object name");
-               if(ob->controllers.first) uiSetCurFont(block, UI_HELV);
-               uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller");
+               if(ob->sensors.first) uiSetCurFont(block, UI_HELVB);
+               uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide sensors");
+               if(ob->sensors.first) uiSetCurFont(block, UI_HELV);
+               uiDefButBitS(block, TOG, OB_ADDSENS, B_ADD_SENS, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Sensor");
                uiBlockEndAlign(block);
                yco-=20;
                
-               if(ob->scaflag & OB_SHOWCONT) {
-               
-                       cont= ob->controllers.first;
-                       while(cont) {
-                               uiBlockSetEmboss(block, UI_EMBOSSM);
-                               uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X,      xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller");
-                               uiDefIconButBitS(block, ICONTOG, CONT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Controller settings");
-               
-                               if(cont->flag & CONT_SHOW) {
-                                       cont->otype= cont->type;
-                                       uiDefButS(block, MENU, B_CHANGE_CONT, controller_pup(),(short)(xco+22), yco, 100, 19, &cont->type, 0, 0, 0, 0, "Controller type");
-                                       but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, cont->name, 0, 31, 0, 0, "Controller name");
-                                       uiButSetFunc(but, make_unique_prop_names_cb, cont->name, (void*) 0);
-               
-                                       ycoo= yco;
-                                       yco= draw_controllerbuttons(cont, block, xco, yco, width);
-                                       if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
-                               }
-                               else {
-                                       cpack(0x999999);
-                                       glRecti(xco+22, yco, xco+width-22,yco+19);
-                                       but= uiDefBut(block, LABEL, 0, controller_name(cont->type), (short)(xco+22), yco, 100, 19, cont, 0, 0, 0, 0, "Controller type");
-                                       uiButSetFunc(but, sca_move_controller, cont, NULL);
-                                       but= uiDefBut(block, LABEL, 0, cont->name,(short)(xco+122), yco,(short)(width-144), 19, cont, 0, 0, 0, 0, "Controller name");
-                                       uiButSetFunc(but, sca_move_controller, cont, NULL);
+               if(ob->scaflag & OB_SHOWSENS) {
+                       
+                       sens= ob->sensors.first;
+                       while(sens) {
+                               if (!(G.buts->scaflag & BUTS_SENS_STATE) ||
+                                       sens->totlinks == 0 ||          /* always display sensor without links so that is can be edited */
+                                       is_sensor_linked(block, sens)) {
+                                       sens->flag |= SENS_VISIBLE;
+                                       uiBlockSetEmboss(block, UI_EMBOSSM);
+                                       uiDefIconButBitS(block, TOG, SENS_DEL, B_DEL_SENS, ICON_X,      xco, yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Delete Sensor");
+                                       uiDefIconButBitS(block, ICONTOG, SENS_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Sensor settings");
+
                                        ycoo= yco;
+                                       if(sens->flag & SENS_SHOW)
+                                       {
+                                               uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(),     (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type");
+                                               but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name");
+                                               uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0);
+
+                                               sens->otype= sens->type;
+                                               yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name);
+                                               if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+                                       }
+                                       else {
+                                               set_col_sensor(sens->type, 1);
+                                               glRecti(xco+22, yco, xco+width-22,yco+19);
+                                               but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, "");
+                                               uiButSetFunc(but, sca_move_sensor, sens, NULL);
+                                               but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, "");
+                                               uiButSetFunc(but, sca_move_sensor, sens, NULL);
+                                       }
+
+                                       but= uiDefIconBut(block, LINK, 0, ICON_LINK,    (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
+                                       uiSetButLink(but, NULL, (void ***)&(sens->links), &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
+
+                                       yco-=20;
                                }
-               
-                               but= uiDefIconBut(block, LINK, 0, ICON_LINK,    (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
-                               uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
-               
-                               uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, cont, LINK_CONTROLLER, 0, 0, 0, "");
-               
-                               yco-=20;
-                               
-                               cont= cont->next;
+                               sens= sens->next;
                        }
                        yco-= 6;
                }
        }
-       
+
        /* ******************************* */
-       xco= 985; yco= 170; width= 280;
+       xco= 1040; yco= 170; width= 280;
        
        uiBlockSetEmboss(block, UI_EMBOSSP);
-       uiDefBlockBut(block, actuator_menu, NULL, "Actuators", xco-10, yco+35, 100, 19, "");
+       uiDefBlockBut(block, actuator_menu, NULL, "Actuators", xco-10, yco+35, 90, 19, "");
        uiBlockSetEmboss(block, UI_EMBOSS);
        uiBlockBeginAlign(block);
-       uiDefButBitS(block, TOG, BUTS_ACT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
-       uiDefButBitS(block, TOG, BUTS_ACT_ACT, B_REDR, "Act", xco+110+(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
-       uiDefButBitS(block, TOG, BUTS_ACT_LINK, B_REDR, "Link", xco+110+2*(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+       uiDefButBitS(block, TOG, BUTS_ACT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+       uiDefButBitS(block, TOG, BUTS_ACT_ACT, B_REDR, "Act", xco+110+(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+       uiDefButBitS(block, TOG, BUTS_ACT_LINK, B_REDR, "Link", xco+110+2*(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+       uiDefButBitS(block, TOG, BUTS_ACT_STATE, B_REDR, "Sta", xco+110+3*(width-100)/4, yco+35, (width-100)/4, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show only actuators connected to active states");
        uiBlockEndAlign(block);
        for(a=0; a<count; a++) {
                ob= (Object *)idar[a];
@@ -2859,34 +3187,38 @@ void logic_buts(void)
                        
                        act= ob->actuators.first;
                        while(act) {
-                               uiBlockSetEmboss(block, UI_EMBOSSM);
-                               uiDefIconButBitS(block, TOG, ACT_DEL, B_DEL_ACT, ICON_X,        xco, yco, 22, 19, &act->flag, 0, 0, 0, 0, "Delete Actuator");
-                               uiDefIconButBitS(block, ICONTOG, ACT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &act->flag, 0, 0, 0, 0, "Actuator settings");
+                               if (!(G.buts->scaflag & BUTS_ACT_STATE) ||
+                                       !(act->flag & ACT_LINKED) ||            /* always display actuators without links so that is can be edited */
+                                       (act->flag & ACT_VISIBLE)) {            /* this actuator has visible connection, display it */
+                                       act->flag |= ACT_VISIBLE;       /* mark the actuator as visible to help implementing the up/down action */
+                                       uiBlockSetEmboss(block, UI_EMBOSSM);
+                                       uiDefIconButBitS(block, TOG, ACT_DEL, B_DEL_ACT, ICON_X,        xco, yco, 22, 19, &act->flag, 0, 0, 0, 0, "Delete Actuator");
+                                       uiDefIconButBitS(block, ICONTOG, ACT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &act->flag, 0, 0, 0, 0, "Actuator settings");
+
+                                       if(act->flag & ACT_SHOW) {
+                                               act->otype= act->type;
+                                               uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob),  (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type");
+                                               but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name");
+                                               uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0);
+
+                                               ycoo= yco;
+                                               yco= draw_actuatorbuttons(ob, act, block, xco, yco, width);
+                                               if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+                                       }
+                                       else {
+                                               set_col_actuator(act->type, 1);
+                                               glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19));
+                                               but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type");
+                                               uiButSetFunc(but, sca_move_actuator, act, NULL);
+                                               but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name");
+                                               uiButSetFunc(but, sca_move_actuator, act, NULL);
+                                               ycoo= yco;
+                                       }
 
-                               if(act->flag & ACT_SHOW) {
-                                       act->otype= act->type;
-                                       uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob),  (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type");
-                                       but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name");
-                                       uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0);
+                                       uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, "");
 
-                                       ycoo= yco;
-                                       yco= draw_actuatorbuttons(act, block, xco, yco, width);
-                                       if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
-                               }
-                               else {
-                                       set_col_actuator(act->type, 1);
-                                       glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19));
-                                       but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type");
-                                       uiButSetFunc(but, sca_move_actuator, act, NULL);
-                                       but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name");
-                                       uiButSetFunc(but, sca_move_actuator, act, NULL);
-                                       ycoo= yco;
+                                       yco-=20;
                                }
-
-                               uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, "");
-
-                               yco-=20;
-
                                act= act->next;
                        }
                        yco-= 6;
index 6582866d9a167b330b158e5ff19c2c040b594884..4fbf92d646e4e875ed52c6f9f669b012ba2b020a 100644 (file)
@@ -2797,6 +2797,10 @@ static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
        line->to= bt;
 }
 
+uiBut *uiFindInlink(uiBlock *block, void *poin)
+{
+       return ui_find_inlink(block, poin);
+}
 
 void uiComposeLinks(uiBlock *block)
 {
index 32946267202f9ebb98b21a23bbf1b7d51d4fc7cc..21c18634e21f30216c5020cf713cc6249c3911c4 100644 (file)
@@ -2324,6 +2324,14 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0;
                BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,activeLayerBitInfo,isInActiveLayer,canvas,converter);
        }
+       // apply the initial state to controllers
+       for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
+       {
+               KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
+               struct Object* blenderobj = converter->FindBlenderObject(gameobj);
+               gameobj->SetState(blenderobj->state);
+       }
+
 #endif //CONVERT_LOGIC
 
        logicbrick_conversionlist->Release();
index f219c3a1472b870d87d76a894cac6e0b8e4c3cd0..c02c2a295952d29f6ec0387c8ee62c21f16b0c4c 100644 (file)
@@ -56,6 +56,7 @@
 #include "KX_ConstraintActuator.h"
 #include "KX_CameraActuator.h"
 #include "KX_GameActuator.h"
+#include "KX_StateActuator.h"
 #include "KX_VisibilityActuator.h"
 #include "KX_SCA_AddObjectActuator.h"
 #include "KX_SCA_EndObjectActuator.h"
@@ -857,7 +858,19 @@ void BL_ConvertActuators(char* maggiename,
                        baseact = tmp_vis_act;
                }
                break;
-               
+
+               case ACT_STATE:
+               {
+                       bStateActuator *sta_act = (bStateActuator *) bact->data;
+                       KX_StateActuator * tmp_sta_act = NULL;
+
+                       tmp_sta_act = 
+                               new KX_StateActuator(gameobj, sta_act->type, sta_act->mask);
+                       
+                       baseact = tmp_sta_act;
+               }
+               break;
+
                case ACT_2DFILTER:
                {
                        bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data;
index a26cfa95b6d2e6556092df3e391fa5bd2b24b5d6..179dd9f847851ea6f9fbb5c51f6d26c9730e39d8 100644 (file)
@@ -161,6 +161,7 @@ void BL_ConvertControllers(
                if (gamecontroller)
                {
                        gamecontroller->SetExecutePriority(executePriority++);
+                       gamecontroller->SetState(bcontr->state_mask);
                        STR_String uniquename = bcontr->name;
                        uniquename += "#CONTR#";
                        uniqueint++;
index 67df5d091aba3b9da7874833772a066ff187fef8..f9fbf2387c4776f1051047e4211663f2ebddca3c 100644 (file)
@@ -53,10 +53,13 @@ SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager* eventmgr,
        : SCA_ISensor(gameobj,eventmgr, T)
 {
        //SetDrawColor(255,0,0);
-       m_alwaysresult = true;
+       Init();
 }
 
-
+void SCA_AlwaysSensor::Init()
+{
+       m_alwaysresult = true;
+}
 
 SCA_AlwaysSensor::~SCA_AlwaysSensor()
 {
index 474ed0254329c98c2c99dc9750cac6889c6818b6..8bf2a8aa98eca079582569067f9e5a81029e59b8 100644 (file)
@@ -45,6 +45,8 @@ public:
        virtual CValue* GetReplica();
        virtual bool Evaluate(CValue* event);
        virtual bool IsPositiveTrigger();
+       virtual void Init();
+
 
        /* --------------------------------------------------------------------- */
        /* Python interface ---------------------------------------------------- */
index 568d0eb4a89133af11bfb66de6f3350a7e62d549..eeca2d7b44c64d7272709d2df4e868fb60f93ee0 100644 (file)
@@ -36,6 +36,7 @@ using namespace std;
 
 SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj,
                                                         PyTypeObject* T) :
+       m_links(0),
        SCA_ILogicBrick(gameobj,T) 
 {
        // nothing to do
@@ -109,3 +110,12 @@ SCA_IActuator::~SCA_IActuator()
        RemoveAllEvents();
 }
 
+void SCA_IActuator::DecLink()
+{
+       m_links--;
+       if (m_links < 0) 
+       {
+               printf("Warning: actuator %s has negative m_links: %d\n", m_name.Ptr(), m_links);
+               m_links = 0;
+       }
+}
index b802aa4b298924621101ca41e30b5dacee318295..774b27c5ad46508115dfae5fc6a2529105d9747a 100644 (file)
 
 class SCA_IActuator : public SCA_ILogicBrick
 {
+       friend class SCA_LogicManager;
 protected:
        std::vector<CValue*> m_events;
+       int                                      m_links;       // number of active links to controllers
+                                                                       // when 0, the actuator is automatically stopped
        void RemoveAllEvents();
 
 public:
@@ -83,6 +86,10 @@ public:
         */
        bool IsNegativeEvent() const;
        virtual ~SCA_IActuator();
+
+       void IncLink() { m_links++; }
+       void DecLink();
+       bool IsNoLink() const { return !m_links; }
 };
 
 #endif //__KX_IACTUATOR
index 5cb62678c6b4bd05f7d4a3b970ad0c881d791ca8..bbe5a51db3c6c828174c3f48e16e7a7d2ecdad62 100644 (file)
@@ -29,6 +29,7 @@
 #include "SCA_IController.h"
 #include "SCA_LogicManager.h"
 #include "SCA_IActuator.h"
+#include "SCA_ISensor.h"
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -37,6 +38,7 @@
 SCA_IController::SCA_IController(SCA_IObject* gameobj,
                                                                 PyTypeObject* T)
        :
+       m_statemask(0),
        SCA_ILogicBrick(gameobj,T)
 {
 }
@@ -45,6 +47,7 @@ SCA_IController::SCA_IController(SCA_IObject* gameobj,
        
 SCA_IController::~SCA_IController()
 {
+       UnlinkAllActuators();
 }
 
 
@@ -65,6 +68,14 @@ const std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators()
 
 void SCA_IController::UnlinkAllSensors()
 {
+       if (IsActive()) 
+       {
+               std::vector<class SCA_ISensor*>::iterator sensit;
+               for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit)
+               {
+                       (*sensit)->DecLink();
+               }
+       }
        m_linkedsensors.clear();
 }
 
@@ -72,6 +83,14 @@ void SCA_IController::UnlinkAllSensors()
 
 void SCA_IController::UnlinkAllActuators()
 {
+       if (IsActive()) 
+       {
+               std::vector<class SCA_IActuator*>::iterator actit;
+               for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit)
+               {
+                       (*actit)->DecLink();
+               }
+       }
        m_linkedactuators.clear();
 }
 
@@ -95,26 +114,94 @@ void SCA_IController::Trigger(SCA_LogicManager* logicmgr)
 void SCA_IController::LinkToActuator(SCA_IActuator* actua)
 {
        m_linkedactuators.push_back(actua);
+       if (IsActive())
+       {
+               actua->IncLink();
+       }
 }
 
 void   SCA_IController::UnlinkActuator(class SCA_IActuator* actua)
 {
        std::vector<class SCA_IActuator*>::iterator actit;
-       std::vector<class SCA_IActuator*>::iterator actfound = m_linkedactuators.end();
        for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit)
        {
                if ((*actit) == actua)
-                       actfound = actit;
+               {
+                       break;
+               }
                
        }
-       if (!(actfound==m_linkedactuators.end()))
+       if (!(actit==m_linkedactuators.end()))
        {
-               m_linkedactuators.erase(actfound);
+               m_linkedactuators.erase(actit);
+               if (IsActive())
+               {
+                       (*actit)->DecLink();
+               }
        }
-       
 }
 
 void SCA_IController::LinkToSensor(SCA_ISensor* sensor)
 {
        m_linkedsensors.push_back(sensor);
+       if (IsActive())
+       {
+               sensor->IncLink();
+       }
+}
+
+void SCA_IController::UnlinkSensor(class SCA_ISensor* sensor)
+{
+       std::vector<class SCA_ISensor*>::iterator sensit;
+       for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit)
+       {
+               if ((*sensit) == sensor)
+               {
+                       break;
+               }
+               
+       }
+       if (!(sensit==m_linkedsensors.end()))
+       {
+               m_linkedsensors.erase(sensit);
+               if (IsActive())
+               {
+                       (*sensit)->DecLink();
+               }
+       }
 }
+
+void SCA_IController::ApplyState(unsigned int state)
+{
+       std::vector<class SCA_IActuator*>::iterator actit;
+       std::vector<class SCA_ISensor*>::iterator sensit;
+
+       if (m_statemask & state) 
+       {
+               if (!IsActive()) 
+               {
+                       // reactive the controller, all the links to actuator are valid again
+                       for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit)
+                       {
+                               (*actit)->IncLink();
+                       }
+                       for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit)
+                       {
+                               (*sensit)->IncLink();
+                       }
+                       SetActive(true);
+               }
+       } else if (IsActive())
+       {
+               for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit)
+               {
+                       (*actit)->DecLink();
+               }
+               for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit)
+               {
+                       (*sensit)->DecLink();
+               }
+               SetActive(false);
+       }
+}
+
index 79e956dec4eb503eed50677107f4c9bebd46274b..f67c0942eb41f5cafdc56e29a99d79df066d5267 100644 (file)
@@ -36,6 +36,7 @@ class SCA_IController : public SCA_ILogicBrick
 protected:
        std::vector<class SCA_ISensor*>         m_linkedsensors;
        std::vector<class SCA_IActuator*>       m_linkedactuators;
+       unsigned int                                            m_statemask;
 public:
        SCA_IController(SCA_IObject* gameobj,PyTypeObject* T);
        virtual ~SCA_IController();
@@ -47,6 +48,9 @@ public:
        void    UnlinkAllSensors();
        void    UnlinkAllActuators();
        void    UnlinkActuator(class SCA_IActuator* actua);
+       void    UnlinkSensor(class SCA_ISensor* sensor);
+       void    SetState(unsigned int state) { m_statemask = state; }
+       void    ApplyState(unsigned int state);
 
 
 };
index 6df9e23f3faef23bbbb98fca0031f678dfebf603..826e7bbdf0e28f7ee4415a1a5d5e75b67dff9ad9 100644 (file)
@@ -40,7 +40,7 @@
 
 MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0);
 
-SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T)
+SCA_IObject::SCA_IObject(PyTypeObject* T): m_state(0), CValue(T)
 {
        m_suspended = false;
 }
@@ -329,6 +329,17 @@ void SCA_IObject::Resume(void)
        }
 }
 
+void SCA_IObject::SetState(unsigned int state)
+{
+       m_state = state;
+       // update the status of the controllers
+       SCA_ControllerList::iterator contit;
+       for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++)
+       {
+               (*contit)->ApplyState(m_state);
+       }
+}
+
 
 
 /* ------------------------------------------------------------------------- */
index e8251e0ceaaf19f9584ddcbcae6e82d315d4d7c0..07b4310a91edbce24c10cee0fcb48b763a3d59cd 100644 (file)
@@ -67,7 +67,12 @@ protected:
         * Ignore updates?
         */
        bool m_suspended;
-       
+
+       /**
+        * current state = bit mask of state that are active
+        */
+       unsigned int                    m_state;
+
 public:
        
        SCA_IObject(PyTypeObject* T=&Type);
@@ -111,7 +116,17 @@ public:
         * Resume progress
         */
        void Resume(void);
-       
+
+       /**
+        * Set the object state
+        */
+       void SetState(unsigned int state);
+
+       /**
+        * Get the object state
+        */
+       unsigned int GetState(void)     { return m_state; }
+
 //     const class MT_Point3&  ConvertPythonPylist(PyObject* pylist);
        
        // here come the python forwarded methods
index 9fdee0c19da47ee464a8c1fdcac5a6dda0170dff..1c29eb27be5bf72b8a2e138cf716e9a8de968786 100644 (file)
@@ -52,6 +52,7 @@ SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
        SCA_ILogicBrick(gameobj,T),
        m_triggered(false)
 {
+       m_links = 0;
        m_suspended = false;
        m_invert = false;
        m_pos_ticks = 0;
@@ -111,6 +112,25 @@ void SCA_ISensor::Resume() {
        m_suspended = false;
 }
 
+void SCA_ISensor::Init() {
+       printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name);
+}
+
+void SCA_ISensor::DecLink() {
+       m_links--;
+       if (m_links < 0) 
+       {
+               printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
+               m_links = 0;
+       }
+       if (!m_links)
+       {
+               // sensor is detached from all controllers, initialize it so that it
+               // is fresh as at startup when it is reattached again.
+               Init();
+       }
+}
+
 /* python integration */
 
 PyTypeObject SCA_ISensor::Type = {
@@ -177,7 +197,8 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr,          CValue* event)
 {
        
        // calculate if a __triggering__ is wanted
-       if (!m_suspended) {
+       // don't evaluate a sensor that is not connected to any controller
+       if (m_links && !m_suspended) {
                bool result = this->Evaluate(event);
                if (result) {
                        logicmgr->AddActivatedSensor(this);     
index e14fb34241a0deb7268bfd9ba23f5e808433ea07..292b2d160aedb88f26df08d798f3c005c05862c0 100644 (file)
@@ -64,6 +64,9 @@ class SCA_ISensor : public SCA_ILogicBrick
        /** Sensor must ignore updates? */
        bool m_suspended;
 
+       /** number of connections to controller */
+       int m_links;
+
        /** Pass the activation on to the logic manager.*/
        void SignalActivation(class SCA_LogicManager* logicmgr);
        
@@ -81,6 +84,7 @@ public:
        void Activate(class SCA_LogicManager* logicmgr,CValue* event);
        virtual bool Evaluate(CValue* event) = 0;
        virtual bool IsPositiveTrigger();
+       virtual void Init();
        
        virtual PyObject* _getattr(const STR_String& attr);
        virtual CValue* GetReplica()=0;
@@ -114,6 +118,12 @@ public:
        /** Resume sensing. */
        void Resume();
 
+       void IncLink()
+               { m_links++; }
+       void DecLink();
+       bool IsNoLink() const 
+               { return !m_links; }
+
        /* Python functions: */
        KX_PYMETHOD_DOC(SCA_ISensor,IsPositive);
        KX_PYMETHOD_DOC(SCA_ISensor,GetUsePosPulseMode);
index b0e7fee130d1d757c6043f545d518ee66c13def2..81938f05af1f3c848764d5113041a94803b890c7 100644 (file)
@@ -64,9 +64,13 @@ std::cout << " button flag "<< m_buttonf     << std::endl;
 std::cout << " hat "           << m_hat                << std::endl;
 std::cout << " hat flag "      << m_hatf               << std::endl;
 */
-       m_istrig=0;
+       Init();
 }
 
+void SCA_JoystickSensor::Init()
+{
+       m_istrig=0;
+}
 
 SCA_JoystickSensor::~SCA_JoystickSensor()
 {
index 2fbe1edf1e73effa3719ab5d850ac67b0e10dc9e..69068da6494762adbb7c76fcd03df055041d1bc4 100644 (file)
@@ -95,6 +95,7 @@ public:
        
        virtual bool Evaluate(CValue* event);
        virtual bool IsPositiveTrigger();
+       virtual void Init();
        
        /* --------------------------------------------------------------------- */
        /* Python interface ---------------------------------------------------- */
index f13b1bcf4c991a0b801324ea7f54d6c87a100999..c6c06846e3bec5b81daf37482e2f451912200ed3 100644 (file)
@@ -62,7 +62,7 @@ SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr,
        if (hotkey == SCA_IInputDevice::KX_ESCKEY)
                keybdmgr->GetInputDevice()->HookEscape();
 //     SetDrawColor(0xff0000ff);
-       m_val=0;
+       Init();
 }
 
 
@@ -71,7 +71,14 @@ SCA_KeyboardSensor::~SCA_KeyboardSensor()
 {
 }
 
-
+void SCA_KeyboardSensor::Init()
+{
+       // this function is used when the sensor is disconnected from all controllers
+       // by the state engine. It reinitializes the sensor as if it was just created.
+       // However, if the target key is pressed when the sensor is reactivated, it
+       // will not generated an event (see remark in Evaluate()).
+       m_val = 0;
+}
 
 CValue* SCA_KeyboardSensor::GetReplica()
 {
index e87eddecd3214350d54ba97016956c0b15b18aa9..b86f6931d276032d07fdb541b64e4e7a969bc51f 100644 (file)
@@ -114,6 +114,8 @@ public:
                                           PyTypeObject* T=&Type );
        virtual ~SCA_KeyboardSensor();
        virtual CValue* GetReplica();
+       virtual void Init();
+
 
        short int GetHotkey();
        virtual bool Evaluate(CValue* event);
index 49f01d643e5a907de75b85da78b22c49493f9e39..fb1a2c29eb67a3e54745c892fad0f22a4cb35031 100644 (file)
@@ -165,6 +165,11 @@ void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshnam
 
 void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor)
 {
+       controllerlist contlist = m_sensorcontrollermapje[sensor];
+       for (controllerlist::const_iterator c= contlist.begin();!(c==contlist.end());c++)
+       {
+               (*c)->UnlinkSensor(sensor);
+       }
     m_sensorcontrollermapje.erase(sensor);
        
        for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin();
@@ -176,6 +181,8 @@ void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor)
 
 void SCA_LogicManager::RemoveController(SCA_IController* controller)
 {
+       controller->UnlinkAllSensors();
+       controller->UnlinkAllActuators();
        std::map<SCA_ISensor*,controllerlist>::iterator sit;
        for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit)
        {
@@ -236,7 +243,8 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime)
                        !(c==contlist.end());c++)
                {
                                SCA_IController* contr = *c;//controllerarray->at(c);
-                               triggeredControllerSet.insert(SmartControllerPtr(contr,0));
+                               if (contr->IsActive())
+                                       triggeredControllerSet.insert(SmartControllerPtr(contr,0));
                }
                //sensor->SetActive(false);
        }
@@ -273,6 +281,16 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
                        
                        (*ia)->SetActive(false);
                        //m_activeactuators.pop_back();
+               } else if ((*ia)->IsNoLink())
+               {
+                       // This actuator has no more links but it still active
+                       // make sure it will get a negative event on next frame to stop it
+                       // Do this check after Update() rather than before to make sure
+                       // that all the actuators that are activated at same time than a state
+                       // actuator have a chance to execute. 
+                       CValue* event = new CBoolValue(false);
+                       (*ia)->RemoveAllEvents();
+                       (*ia)->AddEvent(event);
                }
        }
        
index 8810b7470ed152974c75148b1b163ab6145d3d6e..11e67eda01456046cd9bc33b43017870efe62ca6 100644 (file)
@@ -58,7 +58,6 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr,
 {
        m_mousemode   = mousemode;
        m_triggermode = true;
-       m_val         = 0; /* stores the latest attribute */
 
        switch (m_mousemode) {
        case KX_MOUSESENSORMODE_LEFTBUTTON:
@@ -79,7 +78,12 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr,
        default:
                ; /* ignore, no hotkey */
        }
+       Init();
+}
 
+void SCA_MouseSensor::Init()
+{
+       m_val = 0; /* stores the latest attribute */
 }
 
 SCA_MouseSensor::~SCA_MouseSensor() 
index 86c9d96a80050889cfe00a91296c045147e9699f..26a1c5e3fd2b4faf256177365a6187c10ed8b296 100644 (file)
@@ -96,7 +96,7 @@ class SCA_MouseSensor : public SCA_ISensor
        virtual ~SCA_MouseSensor();
        virtual CValue* GetReplica();
        virtual bool Evaluate(CValue* event);
-
+       virtual void Init();
        virtual bool IsPositiveTrigger();
        short int GetModeKey();
        SCA_IInputDevice::KX_EnumInputs GetHotKey();
index f1fcb18d32e89de47f0c2abb40aa8e011763ebb5..d6eb246ffd2136a9ba5f4d0ca9a45f327ce5829c 100644 (file)
@@ -57,7 +57,6 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
          m_lastresult(false),
          m_range_expr(NULL)
 {
-       m_recentresult=false;
        //CParser pars;
        //pars.SetContext(this->AddRef());
        //CValue* resultval = m_rightexpr->Calculate();
@@ -73,7 +72,12 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
        {
                PrecalculateRangeExpression();
        }
+       Init();
+}
 
+void SCA_PropertySensor::Init()
+{
+       m_recentresult = false;
 }
 
 void SCA_PropertySensor::PrecalculateRangeExpression()
index 81c9b958f25841c1fc13524a8f417d62ede3fe4c..6871cb3afdc5434594fad1d6d8e54c3adf288b2f 100644 (file)
@@ -77,6 +77,7 @@ public:
        virtual void Delete();
        virtual ~SCA_PropertySensor();
        virtual CValue* GetReplica();
+       virtual void Init();
        void    PrecalculateRangeExpression();
        bool    CheckPropertyCondition();
 
index 0e856e0d6bb5b822ec93ba1ae10f457f6461af01..3626522e49a0a02d74d7f8640bfbc037e1432110 100644 (file)
@@ -50,16 +50,9 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr,
                                 PyTypeObject* T)
     : SCA_ISensor(gameobj,eventmgr, T)
 {
-    m_iteration  = 0;
-       m_interval = 0;
-       m_lastdraw   = false;
-       
        // m_basegenerator is never deleted => memory leak
        m_basegenerator = new SCA_RandomNumberGenerator(startseed);
-    m_currentDraw = m_basegenerator->Draw();
-       //registration is done globally, don't do it here
-       //Note: it was probably done to work around a bug in Evaluate(). It is now fixed
-       //RegisterToManager();
+       Init();
 }
 
 
@@ -69,6 +62,13 @@ SCA_RandomSensor::~SCA_RandomSensor()
     /* Nothing to be done here. */
 }
 
+void SCA_RandomSensor::Init()
+{
+    m_iteration  = 0;
+       m_interval = 0;
+       m_lastdraw   = false;
+    m_currentDraw = m_basegenerator->Draw();
+}
 
 
 CValue* SCA_RandomSensor::GetReplica()
index cc54179aa4eb6625d4a3f9f6fbed7fc827f53bac..d29bfb6837a69e798ef3e7fd7376fd36e28716e6 100644 (file)
@@ -54,6 +54,7 @@ public:
        virtual CValue* GetReplica();
        virtual bool Evaluate(CValue* event);
        virtual bool IsPositiveTrigger();
+       virtual void Init();
 
        /* --------------------------------------------------------------------- */
        /* Python interface ---------------------------------------------------- */
index e320453b7aaae50b5628992d5315bcdbd3bc775f..027cb2a0ffa122282a18f5b00712ec348cde341a 100644 (file)
@@ -58,10 +58,15 @@ KX_NetworkMessageSensor::KX_NetworkMessageSensor(
     m_NetworkScene(NetworkScene),
     m_subject(subject),
     m_frame_message_count (0),
-    m_IsUp(false),
     m_BodyList(NULL),
     m_SubjectList(NULL)
 {
+       Init();
+}
+
+void KX_NetworkMessageSensor::Init()
+{
+    m_IsUp = false;
 }
 
 KX_NetworkMessageSensor::~KX_NetworkMessageSensor()
index d051b715aab3a99fa099fb6937d1db9e5777eede..6fd92d17be3ed72ec245d11d8719a14af9734139 100644 (file)
@@ -65,6 +65,7 @@ public:
        virtual CValue* GetReplica();
        virtual bool Evaluate(CValue* event);
        virtual bool IsPositiveTrigger();
+       virtual void Init();
        void EndFrame();
        
        /* ------------------------------------------------------------- */
index 60b90138abeec2ecbc12cbd1410c6d5645d2186a..f306f0dbfbb0f45567dc899ad86216e2f31c417d 100644 (file)
@@ -69,11 +69,14 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr,
          m_gp_canvas(canvas),
          m_kxscene(kxscene)
 {
+       Init();
+}
 
+void KX_MouseFocusSensor::Init()
+{
        m_mouse_over_in_previous_frame = false;
        m_positive_event = false;
        m_hitObject = 0;
-
 }
 
 bool KX_MouseFocusSensor::Evaluate(CValue* event)
index 86f32fbf4be009a6c0e32819ec18a5409532fbba..b011ebe1288e9bc713a6674e746d53481f6af56c 100644 (file)
@@ -68,6 +68,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
         * @attention Overrides default evaluate. 
         */
        virtual bool Evaluate(CValue* event);
+       virtual void Init();
 
        virtual bool IsPositiveTrigger() {
                bool result = m_positive_event;
index 31fffffa3c14651493888ba48e52d0cad9dece4c..987e0b946b20e9774880e18847a0a70247e2503d 100644 (file)
@@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr,
        //sumoObj->setClientObject(&m_client_info);
 }
                        
-
 KX_RadarSensor::~KX_RadarSensor()
 {
        
index a85dc61cac80fc6c49d6e1c10f6d3f8a257fc24e..02b814105b429a82f885d4b1a743c49a4201d483 100644 (file)
@@ -60,17 +60,19 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
                                        m_bFindMaterial(bFindMaterial),
                                        m_distance(distance),
                                        m_scene(ketsjiScene),
-                                       m_bTriggered(false),
-                                       m_axis(axis),
-                                       m_rayHit(false),
-                                       m_hitObject(NULL)
+                                       m_axis(axis)
 
                                
 {
-
+       Init();
 }
 
-
+void KX_RaySensor::Init()
+{
+       m_bTriggered = false;
+       m_rayHit = false;
+       m_hitObject = NULL;
+}
 
 KX_RaySensor::~KX_RaySensor() 
 {
index 8a317ffaa07b27cb28c8ab00110f59b4fd9b9025..f4305b053d147d424bab22acdfbcc54b887b45af 100644 (file)
@@ -66,6 +66,7 @@ public:
 
        virtual bool Evaluate(CValue* event);
        virtual bool IsPositiveTrigger();
+       virtual void Init();
 
        bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
        
index fff33ca82fd2e3cddced83c7fb26814e46fb371b..1526709f42582a61f858b4e91070bbabba8b794e 100644 (file)
@@ -754,8 +754,6 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
        for (SCA_ControllerList::iterator itc = controllers.begin();
                 !(itc==controllers.end());itc++)
        {
-               (*itc)->UnlinkAllSensors();
-               (*itc)->UnlinkAllActuators();
                m_logicmgr->RemoveController(*itc);
        }
 
diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp
new file mode 100644 (file)
index 0000000..95a79f0
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#include "KX_StateActuator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_StateActuator::KX_StateActuator(
+       SCA_IObject* gameobj,
+       int operation,
+       unsigned int mask,
+       PyTypeObject* T
+       ) 
+       : SCA_IActuator(gameobj,T),
+         m_operation(operation),
+         m_mask(mask)
+{
+       // intentionally empty
+}
+
+KX_StateActuator::~KX_StateActuator(
+       void
+       )
+{
+       // intentionally empty
+}
+
+CValue*
+KX_StateActuator::GetReplica(
+       void
+       )
+{
+       KX_StateActuator* replica = new KX_StateActuator(*this);
+       replica->ProcessReplica();
+       // this will copy properties and so on...
+       CValue::AddDataToReplica(replica);
+       return replica;
+}
+
+bool
+KX_StateActuator::Update()
+{
+       bool bNegativeEvent = IsNegativeEvent();
+       unsigned int objMask;
+       
+       RemoveAllEvents();
+       if (bNegativeEvent) return false;
+
+       KX_GameObject *obj = (KX_GameObject*) GetParent();
+       
+       objMask = obj->GetState();
+       switch (m_operation) 
+       {
+       case OP_CPY:
+               objMask = m_mask;
+               break;
+       case OP_SET:
+               objMask |= m_mask;
+               break;
+       case OP_CLR:
+               objMask &= ~m_mask;
+               break;
+       case OP_NEG:
+               objMask ^= m_mask;
+               break;
+       default:
+               // unsupported operation, no  nothing
+               return false;
+       }
+       obj->SetState(objMask);
+       return false;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions                                                          */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject 
+KX_StateActuator::Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "KX_StateActuator",
+       sizeof(KX_StateActuator),
+       0,
+       PyDestructor,
+       0,
+       __getattr,
+       __setattr,
+       0, //&MyPyCompare,
+       __repr,
+       0, //&cvalue_as_number,
+       0,
+       0,
+       0,
+       0
+};
+
+PyParentObject 
+KX_StateActuator::Parents[] = {
+       &KX_StateActuator::Type,
+       &SCA_IActuator::Type,
+       &SCA_ILogicBrick::Type,
+       &CValue::Type,
+       NULL
+};
+
+PyMethodDef 
+KX_StateActuator::Methods[] = {
+       {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation, 
+        METH_VARARGS, SetOperation_doc},
+       {"setMask", (PyCFunction) KX_StateActuator::sPySetMask, 
+        METH_VARARGS, SetMask_doc},
+       {NULL,NULL} //Sentinel
+};
+
+PyObject* 
+KX_StateActuator::_getattr(
+       const STR_String& attr
+       ) 
+{
+       _getattr_up(SCA_IActuator);
+};
+
+
+
+/* set operation ---------------------------------------------------------- */
+char 
+KX_StateActuator::SetOperation_doc[] = 
+"setOperation(op)\n"
+"\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)"
+"\tSet the type of bit operation to be applied on object state mask.\n"
+"\tUse setMask() to specify the bits that will be modified.\n";
+PyObject* 
+
+KX_StateActuator::PySetOperation(PyObject* self, 
+                                   PyObject* args, 
+                                   PyObject* kwds) {
+       int oper;
+
+       if(!PyArg_ParseTuple(args, "i", &oper)) {
+               return NULL;
+       }
+
+       m_operation = oper;
+
+       Py_Return;
+}
+
+/* set mask ---------------------------------------------------------- */
+char 
+KX_StateActuator::SetMask_doc[] = 
+"setMask(mask)\n"
+"\t - mask : bits that will be modified"
+"\tSet the value that defines the bits that will be modified by the operation.\n"
+"\tThe bits that are 1 in the value will be updated in the object state,\n"
+"\tthe bits that are 0 are will be left unmodified expect for the Copy operation\n"
+"\twhich copies the value to the object state.\n";
+PyObject* 
+
+KX_StateActuator::PySetMask(PyObject* self, 
+                                   PyObject* args, 
+                                   PyObject* kwds) {
+       int mask;
+
+       if(!PyArg_ParseTuple(args, "i", &mask)) {
+               return NULL;
+       }
+
+       m_mask = mask;
+
+       Py_Return;
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h
new file mode 100644 (file)
index 0000000..8698e51
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#ifndef __KX_STATEACTUATOR
+#define __KX_STATEACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_StateActuator : public SCA_IActuator
+{
+       Py_Header;
+
+       /** Make visible? */
+       enum {
+               OP_CPY = 0,
+               OP_SET,
+               OP_CLR,
+               OP_NEG
+       };
+       int                             m_operation;
+       unsigned int    m_mask;
+
+ public:
+       
+       KX_StateActuator(
+               SCA_IObject* gameobj,
+               int operation,
+               unsigned int mask,
+               PyTypeObject* T=&Type
+               );
+
+       virtual
+               ~KX_StateActuator(
+                       void
+                       );
+
+       virtual CValue*
+               GetReplica(
+                       void
+                       );
+
+       virtual bool
+               Update();
+
+       /* --------------------------------------------------------------------- */
+       /* Python interface ---------------------------------------------------- */
+       /* --------------------------------------------------------------------- */
+
+       virtual PyObject* _getattr(const STR_String& attr);
+       //KX_PYMETHOD_DOC
+       KX_PYMETHOD_DOC(KX_StateActuator,SetOperation);
+       KX_PYMETHOD_DOC(KX_StateActuator,SetMask);
+};
+
+#endif
+
index 3f185359de00491c81804132d54431b4d6fc357e..56c2780871b29dc811be3c3272b0d374c4427a0e 100644 (file)
@@ -77,18 +77,14 @@ KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj
 :SCA_ISensor(gameobj,eventmgr,T),
 m_touchedpropname(touchedpropname),
 m_bFindMaterial(bFindMaterial),
-m_eventmgr(eventmgr),
+m_eventmgr(eventmgr)
 /*m_sumoObj(sumoObj),*/
-m_bCollision(false),
-m_bTriggered(false),
-m_bLastTriggered(false)
 {
 //     KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr;
 //     m_resptable = touchmgr->GetResponseTable();
        
 //     m_solidHandle = m_sumoObj->getObjectHandle();
 
-       m_hitObject =  NULL;
        m_colliders = new CListValue();
        
        KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
@@ -98,8 +94,16 @@ m_bLastTriggered(false)
        
        m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController());
        MT_assert( !gameobj->GetPhysicsController() || m_physCtrl );
+       Init();
 }
 
+void KX_TouchSensor::Init()
+{
+       m_bCollision = false;
+       m_bTriggered = false;
+       m_bLastTriggered = false;
+       m_hitObject =  NULL;
+}
 
 KX_TouchSensor::~KX_TouchSensor()
 {
index f594196628a1292c40329456e81d5ef45bc6529d..056440ccd6c289b25e2bc50c992151ddaf5a858f 100644 (file)
@@ -72,6 +72,7 @@ public:
        virtual CValue* GetReplica();
        virtual void SynchronizeTransform();
        virtual bool Evaluate(CValue* event);
+       virtual void Init();
        virtual void ReParent(SCA_IObject* parent);
        
        virtual void RegisterSumo(KX_TouchEventManager* touchman);