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.
This commit is contained in:
Benoit Bolsee 2008-06-22 14:23:57 +00:00
parent 1ee7a20b93
commit 5372def2b0
49 changed files with 1119 additions and 199 deletions

@ -474,6 +474,9 @@
<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>
@ -695,6 +698,9 @@
<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>

@ -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... */

@ -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! */

@ -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 */
}

@ -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 */

@ -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);

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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,78 +2931,27 @@ void logic_buts(void)
uiClearButLock();
idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
/* ******************************* */
xco= 375; yco= 170; width= 230;
uiBlockSetEmboss(block, UI_EMBOSSP);
uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 80, 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");
uiBlockEndAlign(block);
/* 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];
uiClearButLock();
uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
if( (ob->scavisflag & OB_VIS_SENS) == 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");
uiBlockEndAlign(block);
yco-=20;
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");
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;
sens= sens->next;
}
yco-= 6;
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= 675; yco= 170; width= 230;
xco= 695; yco= 170; width= 275;
uiBlockSetEmboss(block, UI_EMBOSSP);
uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, "");
@ -2785,59 +2979,193 @@ void logic_buts(void)
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;
/* 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;
}
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;
/* 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 {
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);
ycoo= yco;
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);
yco-=35;
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;
/* 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);
cont= cont->next;
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;
}
}
yco-= 6;
}
}
/* ******************************* */
xco= 985; yco= 170; width= 280;
xco= 375; yco= 170; width= 250;
uiBlockSetEmboss(block, UI_EMBOSSP);
uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 70, 19, "");
uiBlockSetEmboss(block, UI_EMBOSS);
uiBlockBeginAlign(block);
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);
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;
/* 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");
uiBlockEndAlign(block);
yco-=20;
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;
}
sens= sens->next;
}
yco-= 6;
}
}
/* ******************************* */
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);
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(act, block, xco, yco, width);
if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
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;
}
uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, "");
yco-=20;
}
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;
}
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;

@ -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)
{

@ -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();

@ -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;

@ -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++;

@ -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()
{

@ -45,6 +45,8 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
virtual void Init();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */

@ -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;
}
}

@ -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

@ -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);
}
}

@ -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);
};

@ -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);
}
}
/* ------------------------------------------------------------------------- */

@ -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

@ -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);

@ -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);

@ -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()
{

@ -95,6 +95,7 @@ public:
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
virtual void Init();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */

@ -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()
{

@ -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);

@ -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);
}
}

@ -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()

@ -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();

@ -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()

@ -77,6 +77,7 @@ public:
virtual void Delete();
virtual ~SCA_PropertySensor();
virtual CValue* GetReplica();
virtual void Init();
void PrecalculateRangeExpression();
bool CheckPropertyCondition();

@ -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()

@ -54,6 +54,7 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
virtual void Init();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */

@ -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()

@ -65,6 +65,7 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
virtual void Init();
void EndFrame();
/* ------------------------------------------------------------- */

@ -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)

@ -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;

@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr,
//sumoObj->setClientObject(&m_client_info);
}
KX_RadarSensor::~KX_RadarSensor()
{

@ -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()
{

@ -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);

@ -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);
}

@ -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;
}

@ -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

@ -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()
{

@ -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);