Skip to content

Commit

Permalink
Input|Bindings: Mark toggles triggered, check the flag for the Attack…
Browse files Browse the repository at this point in the history
… control

The Attack control is not an impulse control. This means that if the key is
not held down when a sharp tick occurs, it is not considered to be active
even though it has been pressed and released since the previous sharp
tick.

The trigger flags are drawn in the key state visualization as purple marks.
  • Loading branch information
skyjake committed Feb 17, 2012
1 parent eadf263 commit 9101a1d
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 18 deletions.
5 changes: 3 additions & 2 deletions doomsday/engine/api/dd_share.h
Expand Up @@ -1712,8 +1712,9 @@ enum {

/// Control type.
typedef enum controltype_e {
CTLT_NUMERIC,
CTLT_IMPULSE
CTLT_NUMERIC, ///< Control with a numeric value determined by current device state.
CTLT_NUMERIC_TRIGGERED, ///< Numeric, but accepts triggered states as well.
CTLT_IMPULSE ///< Always accepts triggered states.
} controltype_t;

/**
Expand Down
3 changes: 2 additions & 1 deletion doomsday/engine/portable/include/b_device.h
Expand Up @@ -65,7 +65,8 @@ void B_DestroyDeviceBinding(dbinding_t* cb);
void B_DeviceBindingToString(const dbinding_t* b, ddstring_t* str);
void B_EvaluateDeviceBindingList(int localNum, dbinding_t* listRoot,
float* pos, float* relativeOffset,
struct bcontext_s* controlClass);
struct bcontext_s* controlClass,
boolean allowTriggered);

#endif // __DOOMSDAY_BIND_DEVICE_H__

2 changes: 2 additions & 0 deletions doomsday/engine/portable/include/dd_input.h
Expand Up @@ -122,6 +122,8 @@ typedef struct inputdevassoc_s {
#define IDAF_EXPIRED 0x1 // The state has expired. The device is considered to remain
// in default state until the flag gets cleared (which happens when
// the real device state returns to its default).
#define IDAF_TRIGGERED 0x2 // The state has been triggered. This is cleared when someone checks
// the device state. (Only for toggles.)

// Input device axis types.
enum
Expand Down
1 change: 1 addition & 0 deletions doomsday/engine/portable/include/p_control.h
Expand Up @@ -38,6 +38,7 @@ int P_GetImpulseControlState(int playerNum, int control);
typedef struct playercontrol_s {
int id;
controltype_t type;
boolean isTriggerable; ///< Accepts triggered states in addition to active ones.
char* name;
char* bindContextName;
} playercontrol_t;
Expand Down
3 changes: 3 additions & 0 deletions doomsday/engine/portable/src/b_command.c
Expand Up @@ -429,6 +429,9 @@ boolean B_TryCommandBinding(evbinding_t* eb, ddevent_t* event, struct bcontext_s
if(eventClass && dev->keys[eb->id].assoc.bContext != eventClass)
return false; // Shadowed by a more important active class.

// We're checking it, so clear the triggered flag.
dev->keys[eb->id].assoc.flags &= ~IDAF_TRIGGERED;

// Is the state as required?
switch(eb->state)
{
Expand Down
1 change: 1 addition & 0 deletions doomsday/engine/portable/src/b_context.c
Expand Up @@ -237,6 +237,7 @@ void B_UpdateDeviceStateAssociations(void)
{
// No longer valid.
dev->keys[j].assoc.flags |= IDAF_EXPIRED;
dev->keys[j].assoc.flags &= ~IDAF_TRIGGERED; // Not any more.
DD_ClearKeyRepeaterForKey(j);
}
}
Expand Down
11 changes: 8 additions & 3 deletions doomsday/engine/portable/src/b_device.c
Expand Up @@ -278,7 +278,8 @@ void B_DestroyDeviceBinding(dbinding_t* cb)
}
}

void B_EvaluateDeviceBindingList(int localNum, dbinding_t* listRoot, float* pos, float* relativeOffset, bcontext_t* controlClass)
void B_EvaluateDeviceBindingList(int localNum, dbinding_t* listRoot, float* pos, float* relativeOffset,
bcontext_t* controlClass, boolean allowTriggered)
{
dbinding_t* cb;
int i;
Expand Down Expand Up @@ -332,8 +333,12 @@ void B_EvaluateDeviceBindingList(int localNum, dbinding_t* listRoot, float* pos,
if(dev->keys[cb->id].assoc.flags & IDAF_EXPIRED)
break;

devicePos = (dev->keys[cb->id].isDown? 1.0f : 0.0f);
devicePos = (dev->keys[cb->id].isDown ||
(allowTriggered && (dev->keys[cb->id].assoc.flags & IDAF_TRIGGERED))? 1.0f : 0.0f);
deviceTime = dev->keys[cb->id].time;

// We've checked it, so clear the flag.
dev->keys[cb->id].assoc.flags &= ~IDAF_TRIGGERED;
break;

case CBD_AXIS:
Expand Down Expand Up @@ -422,7 +427,7 @@ void B_EvaluateDeviceBindingList(int localNum, dbinding_t* listRoot, float* pos,
*pos = 0;
}

// Clamp appropriately.
// Clamp to the normalized range.
*pos = MINMAX_OF(-1.0f, *pos, 1.0f);
}

Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/src/b_util.c
Expand Up @@ -466,7 +466,7 @@ boolean B_CheckCondition(statecondition_t* cond, int localNum, bcontext_t* conte
// Evaluate the current state of the modifier (in this context).
float pos = 0, relative = 0;
dbinding_t* binds = &B_GetControlBinding(context, cond->id)->deviceBinds[localNum];
B_EvaluateDeviceBindingList(localNum, binds, &pos, &relative, context);
B_EvaluateDeviceBindingList(localNum, binds, &pos, &relative, context, false /*no triggered*/);
if((cond->state == EBTOG_DOWN && fabs(pos) > .5) ||
(cond->state == EBTOG_UP && fabs(pos) < .5))
return fulfilled;
Expand Down
24 changes: 22 additions & 2 deletions doomsday/engine/portable/src/dd_input.c
Expand Up @@ -625,9 +625,14 @@ void I_TrackInput(ddevent_t *ev, timespan_t ticLength)
key->time = Sys_GetRealTime();
}

// We can clear the expiration when the key is released.
if(!key->isDown)
if(key->isDown)
{
// This will get cleared after the state is checked by someone.
key->assoc.flags |= IDAF_TRIGGERED;
}
else
{
// We can clear the expiration when the key is released.
key->assoc.flags &= ~IDAF_EXPIRED;
}
}
Expand Down Expand Up @@ -662,6 +667,7 @@ void I_ClearDeviceContextAssociations(void)
{
dev->keys[j].assoc.prevBContext = dev->keys[j].assoc.bContext;
dev->keys[j].assoc.bContext = NULL;
dev->keys[j].assoc.flags &= ~IDAF_TRIGGERED;
}
// Axes.
for(j = 0; j < dev->numAxes; ++j)
Expand Down Expand Up @@ -1491,6 +1497,7 @@ void Rend_RenderKeyStateVisual(inputdev_t* device, uint keyID, const Point2Raw*
const float upColor[] = { .3f, .3f, .3f, .6f };
const float downColor[] = { .3f, .3f, 1, .6f };
const float expiredMarkColor[] = { 1, 0, 0, 1 };
const float triggeredMarkColor[] = { 1, 0, 1, 1 };
const char* keyLabel = NULL;
const inputdevkey_t* key;
char keyLabelBuf[2];
Expand Down Expand Up @@ -1574,6 +1581,19 @@ void Rend_RenderKeyStateVisual(inputdev_t* device, uint keyID, const Point2Raw*
glEnd();
}

// Mark triggered?
if(key->assoc.flags & IDAF_TRIGGERED)
{
const int markSize = .5f + MIN_OF(textGeom.size.width, textGeom.size.height) / 3.f;

glColor3fv(triggeredMarkColor);
glBegin(GL_TRIANGLES);
glVertex2i(0, 0);
glVertex2i(markSize, 0);
glVertex2i(0, markSize);
glEnd();
}

endDrawStateForVisual(&origin);

Str_Free(&label);
Expand Down
13 changes: 5 additions & 8 deletions doomsday/engine/portable/src/p_control.c
Expand Up @@ -170,6 +170,7 @@ void P_NewPlayerControl(int id, controltype_t type, const char *name, const char
pc->id = id;
pc->type = type;
pc->name = strdup(name);
pc->isTriggerable = (type == CTLT_NUMERIC_TRIGGERED || type == CTLT_IMPULSE);
pc->bindContextName = strdup(bindContext);
// Also allocate the impulse and double-click counters.
controlCounts[pc - playerControls] = M_Calloc(sizeof(controlcounter_t));
Expand Down Expand Up @@ -333,15 +334,11 @@ void P_GetControlState(int playerNum, int control, float* pos, float* relativeOf
struct bcontext_s* bc = 0;
struct dbinding_s* binds = 0;
int localNum;
playercontrol_t* pc = P_PlayerControlById(control);

#if _DEBUG
// Check that this is really a numeric control.
{
playercontrol_t* pc = P_PlayerControlById(control);
assert(pc);
assert(pc->type == CTLT_NUMERIC);
}
#endif
assert(pc);
assert(pc->type == CTLT_NUMERIC || pc->type == CTLT_NUMERIC_TRIGGERED);

// Ignore NULLs.
if(!pos) pos = &tmp;
Expand All @@ -352,7 +349,7 @@ void P_GetControlState(int playerNum, int control, float* pos, float* relativeOf
// P_ConsoleToLocal() is called here.
localNum = P_ConsoleToLocal(playerNum);
binds = B_GetControlDeviceBindings(localNum, control, &bc);
B_EvaluateDeviceBindingList(localNum, binds, pos, relativeOffset, bc);
B_EvaluateDeviceBindingList(localNum, binds, pos, relativeOffset, bc, pc->isTriggerable);

// Mark for double-clicks.
P_MaintainControlDoubleClicks(playerNum, P_PlayerControlIndexForId(control), *pos);
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/common/src/g_controls.c
Expand Up @@ -185,7 +185,7 @@ void G_ControlRegister(void)
P_NewPlayerControl(CTL_LOOK, CTLT_NUMERIC, "look", "game");
P_NewPlayerControl(CTL_SPEED, CTLT_NUMERIC, "speed", "game");
P_NewPlayerControl(CTL_MODIFIER_1, CTLT_NUMERIC, "strafe", "game");
P_NewPlayerControl(CTL_ATTACK, CTLT_NUMERIC, "attack", "game");
P_NewPlayerControl(CTL_ATTACK, CTLT_NUMERIC_TRIGGERED, "attack", "game");
P_NewPlayerControl(CTL_USE, CTLT_IMPULSE, "use", "game");
P_NewPlayerControl(CTL_LOOK_CENTER, CTLT_IMPULSE, "lookcenter", "game");
P_NewPlayerControl(CTL_FALL_DOWN, CTLT_IMPULSE, "falldown", "game");
Expand Down

0 comments on commit 9101a1d

Please sign in to comment.