Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Bolsee <benoit.bolsee@online.be>2008-06-22 18:23:57 +0400
committerBenoit Bolsee <benoit.bolsee@online.be>2008-06-22 18:23:57 +0400
commit5372def2b069699809cf9439381b03364137adb5 (patch)
treeafe69a88cca198ee85617ee284c6fc5be48671c9
parent1ee7a20b93ee3c640b119e1a650e49dcb0f97de9 (diff)
BGE patch: add state engine support in the logic bricks.
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.
-rw-r--r--projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj6
-rw-r--r--source/blender/blenkernel/intern/sca.c3
-rw-r--r--source/blender/blenloader/intern/readfile.c12
-rw-r--r--source/blender/blenloader/intern/writefile.c3
-rw-r--r--source/blender/include/BIF_butspace.h2
-rw-r--r--source/blender/include/BIF_interface.h1
-rw-r--r--source/blender/include/butspace.h4
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h8
-rw-r--r--source/blender/makesdna/DNA_controller_types.h3
-rw-r--r--source/blender/makesdna/DNA_object_types.h6
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h1
-rw-r--r--source/blender/src/buttons_logic.c626
-rw-r--r--source/blender/src/interface.c4
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp8
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp15
-rw-r--r--source/gameengine/Converter/KX_ConvertControllers.cpp1
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysSensor.cpp7
-rw-r--r--source/gameengine/GameLogic/SCA_AlwaysSensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.cpp10
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.h7
-rw-r--r--source/gameengine/GameLogic/SCA_IController.cpp97
-rw-r--r--source/gameengine/GameLogic/SCA_IController.h4
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.cpp13
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.h19
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.cpp23
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.h10
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.cpp6
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.h1
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardSensor.cpp11
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardSensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_LogicManager.cpp20
-rw-r--r--source/gameengine/GameLogic/SCA_MouseSensor.cpp6
-rw-r--r--source/gameengine/GameLogic/SCA_MouseSensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp6
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.h1
-rw-r--r--source/gameengine/GameLogic/SCA_RandomSensor.cpp16
-rw-r--r--source/gameengine/GameLogic/SCA_RandomSensor.h1
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp7
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h1
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.h1
-rw-r--r--source/gameengine/Ketsji/KX_RadarSensor.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.h1
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_StateActuator.cpp207
-rw-r--r--source/gameengine/Ketsji/KX_StateActuator.h83
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.h1
49 files changed, 1112 insertions, 192 deletions
diff --git a/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj
index c8173750bdc..af0ba74497a 100644
--- a/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj
+++ b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj
@@ -475,6 +475,9 @@
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
@@ -696,6 +699,9 @@
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>
<File
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index 92544f19721..16ca5d7542d 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -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... */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index fa7cbb06139..9cfce5e34fa 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -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! */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 2595b95bbf0..9f28e13ff7b 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -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 */
}
diff --git a/source/blender/include/BIF_butspace.h b/source/blender/include/BIF_butspace.h
index cbbd8013c82..f0b37814947 100644
--- a/source/blender/include/BIF_butspace.h
+++ b/source/blender/include/BIF_butspace.h
@@ -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 */
diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h
index fbd4e4ecd91..3da4466d4d3 100644
--- a/source/blender/include/BIF_interface.h
+++ b/source/blender/include/BIF_interface.h
@@ -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);
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 7571d64be91..c0542e3f34c 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -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
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index a326f5b01d6..417ba540e2c 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h
index 95c9b0d0cf7..cc9215e7d14 100644
--- a/source/blender/makesdna/DNA_controller_types.h
+++ b/source/blender/makesdna/DNA_controller_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 83168248b9a..c4e8cb4925b 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index 90e2b8f9f41..3fd57a85349 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -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
diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c
index b6877b2e2b7..c4fc17bc4d0 100644
--- a/source/blender/src/buttons_logic.c
+++ b/source/blender/src/buttons_logic.c
@@ -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;
diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c
index 6582866d9a1..4fbf92d646e 100644
--- a/source/blender/src/interface.c
+++ b/source/blender/src/interface.c
@@ -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)
{
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 32946267202..21c18634e21 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -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();
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index f219c3a1472..c02c2a29595 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -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;
diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp
index a26cfa95b6d..179dd9f8478 100644
--- a/source/gameengine/Converter/KX_ConvertControllers.cpp
+++ b/source/gameengine/Converter/KX_ConvertControllers.cpp
@@ -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++;
diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
index 67df5d091ab..f9fbf2387c4 100644
--- a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
@@ -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()
{
diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.h b/source/gameengine/GameLogic/SCA_AlwaysSensor.h
index 474ed025432..8bf2a8aa98e 100644
--- a/source/gameengine/GameLogic/SCA_AlwaysSensor.h
+++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.h
@@ -45,6 +45,8 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
+
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */
diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp
index 568d0eb4a89..eeca2d7b44c 100644
--- a/source/gameengine/GameLogic/SCA_IActuator.cpp
+++ b/source/gameengine/GameLogic/SCA_IActuator.cpp
@@ -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;
+ }
+}
diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h
index b802aa4b298..774b27c5ad4 100644
--- a/source/gameengine/GameLogic/SCA_IActuator.h
+++ b/source/gameengine/GameLogic/SCA_IActuator.h
@@ -34,8 +34,11 @@
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
diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp
index 5cb62678c6b..bbe5a51db3c 100644
--- a/source/gameengine/GameLogic/SCA_IController.cpp
+++ b/source/gameengine/GameLogic/SCA_IController.cpp
@@ -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);
+ }
+}
+
diff --git a/source/gameengine/GameLogic/SCA_IController.h b/source/gameengine/GameLogic/SCA_IController.h
index 79e956dec4e..f67c0942eb4 100644
--- a/source/gameengine/GameLogic/SCA_IController.h
+++ b/source/gameengine/GameLogic/SCA_IController.h
@@ -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);
};
diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp
index 6df9e23f3fa..826e7bbdf0e 100644
--- a/source/gameengine/GameLogic/SCA_IObject.cpp
+++ b/source/gameengine/GameLogic/SCA_IObject.cpp
@@ -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);
+ }
+}
+
/* ------------------------------------------------------------------------- */
diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h
index e8251e0ceaa..07b4310a91e 100644
--- a/source/gameengine/GameLogic/SCA_IObject.h
+++ b/source/gameengine/GameLogic/SCA_IObject.h
@@ -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
diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp
index 9fdee0c19da..1c29eb27be5 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.cpp
+++ b/source/gameengine/GameLogic/SCA_ISensor.cpp
@@ -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);
diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h
index e14fb34241a..292b2d160ae 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.h
+++ b/source/gameengine/GameLogic/SCA_ISensor.h
@@ -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);
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
index b0e7fee130d..81938f05af1 100644
--- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
@@ -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()
{
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h
index 2fbe1edf1e7..69068da6494 100644
--- a/source/gameengine/GameLogic/SCA_JoystickSensor.h
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h
@@ -95,6 +95,7 @@ public:
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */
diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
index f13b1bcf4c9..c6c06846e3b 100644
--- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
@@ -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()
{
diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.h b/source/gameengine/GameLogic/SCA_KeyboardSensor.h
index e87eddecd32..b86f6931d27 100644
--- a/source/gameengine/GameLogic/SCA_KeyboardSensor.h
+++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.h
@@ -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);
diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp
index 49f01d643e5..fb1a2c29eb6 100644
--- a/source/gameengine/GameLogic/SCA_LogicManager.cpp
+++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp
@@ -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);
}
}
diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
index 8810b7470ed..11e67eda014 100644
--- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
@@ -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()
diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h
index 86c9d96a800..26a1c5e3fd2 100644
--- a/source/gameengine/GameLogic/SCA_MouseSensor.h
+++ b/source/gameengine/GameLogic/SCA_MouseSensor.h
@@ -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();
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index f1fcb18d32e..d6eb246ffd2 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -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()
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h
index 81c9b958f25..6871cb3afdc 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.h
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.h
@@ -77,6 +77,7 @@ public:
virtual void Delete();
virtual ~SCA_PropertySensor();
virtual CValue* GetReplica();
+ virtual void Init();
void PrecalculateRangeExpression();
bool CheckPropertyCondition();
diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
index 0e856e0d6bb..3626522e49a 100644
--- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
@@ -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()
diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.h b/source/gameengine/GameLogic/SCA_RandomSensor.h
index cc54179aa4e..d29bfb6837a 100644
--- a/source/gameengine/GameLogic/SCA_RandomSensor.h
+++ b/source/gameengine/GameLogic/SCA_RandomSensor.h
@@ -54,6 +54,7 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
index e320453b7aa..027cb2a0ffa 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
@@ -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()
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
index d051b715aab..6fd92d17be3 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
@@ -65,6 +65,7 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
void EndFrame();
/* ------------------------------------------------------------- */
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
index 60b90138abe..f306f0dbfbb 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
@@ -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)
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
index 86f32fbf4be..b011ebe1288 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
@@ -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;
diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp
index 31fffffa3c1..987e0b946b2 100644
--- a/source/gameengine/Ketsji/KX_RadarSensor.cpp
+++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp
@@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr,
//sumoObj->setClientObject(&m_client_info);
}
-
KX_RadarSensor::~KX_RadarSensor()
{
diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp
index a85dc61cac8..02b814105b4 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.cpp
+++ b/source/gameengine/Ketsji/KX_RaySensor.cpp
@@ -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()
{
diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h
index 8a317ffaa07..f4305b053d1 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.h
+++ b/source/gameengine/Ketsji/KX_RaySensor.h
@@ -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);
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index fff33ca82fd..1526709f425 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -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
index 00000000000..95a79f0c480
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_StateActuator.cpp
@@ -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
index 00000000000..8698e51b2c1
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_StateActuator.h
@@ -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
+
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp
index 3f185359de0..56c2780871b 100644
--- a/source/gameengine/Ketsji/KX_TouchSensor.cpp
+++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp
@@ -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()
{
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h
index f594196628a..056440ccd6c 100644
--- a/source/gameengine/Ketsji/KX_TouchSensor.h
+++ b/source/gameengine/Ketsji/KX_TouchSensor.h
@@ -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);