Skip to content

Commit

Permalink
Refactor|PlayerImpulse: Continued PlayerImpulse remodeling
Browse files Browse the repository at this point in the history
Evidently double-clicks still aren't working correctly. Hmm...
  • Loading branch information
danij-deng committed Nov 8, 2014
1 parent e992bed commit d46165f
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 228 deletions.
2 changes: 1 addition & 1 deletion doomsday/client/include/ui/bindcontext.h
Expand Up @@ -30,7 +30,7 @@ typedef int (*FallbackResponderFunc)(event_t *);
typedef int (*DDFallbackResponderFunc)(ddevent_t const *);
// todo ends

struct PlayerImpulse;
class PlayerImpulse;

/**
* Contextualized grouping of input (and windowing system) event bindings.
Expand Down
20 changes: 10 additions & 10 deletions doomsday/client/include/ui/inputsystem.h
Expand Up @@ -170,7 +170,7 @@ class InputSystem : public de::System
DENG2_ERROR(MissingContextError);

/**
* Try to make a new command binding.
* Try to make a new (console) command binding.
*
* @param eventDesc Textual descriptor for the event, with the relevant
* context for the would-be binding encoded.
Expand Down Expand Up @@ -214,14 +214,15 @@ class InputSystem : public de::System
void clearAllContexts();

/**
* Returns the total number of binding contexts in the system.
* Returns @c true if the symbolic @a name references a known context.
*/
int contextCount() const;
bool hasContext(de::String const &name) const;

/**
* Returns @c true if the symbolic @a name references a known context.
* Creates a new binding context. The new context has the highest priority
* of all existing contexts, and is inactive.
*/
bool hasContext(de::String const &name) const;
BindContext *newContext(de::String const &name);

/**
* Lookup a binding context by symbolic @a name.
Expand All @@ -240,15 +241,14 @@ class InputSystem : public de::System
int contextPositionOf(BindContext *context) const;

/**
* Creates a new binding context. The new context has the highest priority
* of all existing contexts, and is inactive.
* Iterate through all the BindContexts from highest to lowest priority.
*/
BindContext *newContext(de::String const &name);
de::LoopResult forAllContexts(std::function<de::LoopResult (BindContext &)> func) const;

/**
* Iterate through all the BindContexts from highest to lowest priority.
* Returns the total number of binding contexts in the system.
*/
de::LoopResult forAllContexts(std::function<de::LoopResult (BindContext &)> func) const;
int contextCount() const;

// ---

Expand Down
104 changes: 63 additions & 41 deletions doomsday/client/include/ui/playerimpulse.h
Expand Up @@ -25,76 +25,98 @@

/**
* Describes a player interaction impulse.
*
* @todo Is "take" is the wrong verb in this context?
* Player impulses are acted upon by the player Brain (on game side). Does it make
* sense for a "brain" to "consume" an impulse? (Also note established convention
* in Qt containers for removing an element from the container). Perhaps we need
* another abstraction here? -ds
*
* @todo cleanup client/server confusion. On server side, each player will have a
* local model of a remote human player's impulses. However, Double-clicks can be
* handled entirely on client side. -ds
*/
struct PlayerImpulse
class PlayerImpulse
{
int id;
public:
impulsetype_t type;
de::String name;
de::String bindContextName;

short booleanCounts[DDMAXPLAYERS];
public:
PlayerImpulse(int id, impulsetype_t type, de::String const &name,
de::String bindContextName);

bool isTriggerable() const;

/**
* Returns the unique identifier of the impulse.
*/
int id() const;

/**
* Returns the symbolic name of the impulse. This name is used for resolving
* or generating textual binding descriptors.
*/
de::String name() const;

/**
* Returns the symbolic name of the attributed binding context.
*/
de::String bindContextName() const;

#ifdef __CLIENT__
/**
* Double-"clicks" actually mean double activations that occur within the double-click
* threshold. This is to allow double-clicks also from the numeric impulses.
* Returns @c true if one or more ImpulseBindings exist in @em any bindContext.
*
* @param playerNum Console/player number.
*/
struct DoubleClick
{
enum State
{
None,
Positive,
Negative
};

bool triggered = false; //< True if double-click has been detected.
uint previousClickTime = 0; //< Previous time an activation occurred.
State lastState = None; //< State at the previous time the check was made.
State previousClickState = None; /** Previous click state. When duplicated, triggers
the double click. */
} doubleClicks[DDMAXPLAYERS];
bool haveBindingsFor(int playerNum) const;
#endif

PlayerImpulse(int id, impulsetype_t type, de::String const &name, de::String bindContextName)
: id (id)
, type (type)
, name (name)
, bindContextName(bindContextName)
{
de::zap(booleanCounts);
}
public:
/**
* @param playerNum Console/player number.
*/
void triggerBoolean(int playerNum);

/**
* Returns @c true if the impulse is triggerable.
* @param playerNum Console/player number.
*/
inline bool isTriggerable() const {
return (type == IT_NUMERIC_TRIGGERED || type == IT_BOOLEAN);
}
int takeBoolean(int playerNum);

#ifdef __CLIENT__
/**
* Updates the double-click state of an impulse and marks it as double-clicked
* when the double-click condition is met.
*
* @param playerNum Player/console number.
* @param pos State of the impulse.
* @param playerNum Console/player number.
* @param pos
* @param relOffset
*/
void maintainDoubleClicks(int playerNum, float pos);
void takeNumeric(int playerNum, float *pos = nullptr, float *relOffset = nullptr);

/**
* @param playerNum Console/player number.
*/
int takeDoubleClick(int playerNum);

/**
* @param playerNum Console/player number. Use @c < 0 || >= DDMAXPLAYERS for all.
*/
void clearAccumulation(int playerNum = -1 /*all local players*/);

public:

/**
* Register the console commands and variables of this module.
*/
static void consoleRegister();

#endif

private:
DENG2_PRIVATE(d)
};

void P_ImpulseShutdown();

PlayerImpulse *P_ImpulseById(int id);
PlayerImpulse *P_ImpulsePtr(int id);

PlayerImpulse *P_ImpulseByName(de::String const &name);

Expand Down
8 changes: 4 additions & 4 deletions doomsday/client/src/con_config.cpp
Expand Up @@ -206,7 +206,7 @@ static bool writeBindingsState(Path const &filePath)
isys.forAllContexts([&isys, &file] (BindContext &context)
{
// Commands.
context.forAllCommandBindings([&isys, &context, &file] (CommandBinding &bind)
context.forAllCommandBindings([&isys, &file, &context] (CommandBinding &bind)
{
fprintf(file, "bindevent \"%s:%s\" \"", context.name().toUtf8().constData(),
isys.composeBindsFor(bind).toUtf8().constData());
Expand All @@ -216,13 +216,13 @@ static bool writeBindingsState(Path const &filePath)
});

// Impulses.
context.forAllImpulseBindings([&isys, &context, &file] (ImpulseBinding &bind)
context.forAllImpulseBindings([&isys, &file, &context] (ImpulseBinding &bind)
{
PlayerImpulse const *impulse = P_ImpulseById(bind.impulseId);
PlayerImpulse const *impulse = P_ImpulsePtr(bind.impulseId);
DENG2_ASSERT(impulse);

fprintf(file, "bindcontrol local%i-%s \"%s\"\n",
bind.localPlayer + 1, impulse->name.toUtf8().constData(),
bind.localPlayer + 1, impulse->name().toUtf8().constData(),
isys.composeBindsFor(bind).toUtf8().constData());
return LoopContinue;
});
Expand Down
6 changes: 3 additions & 3 deletions doomsday/client/src/ui/bindcontext.cpp
Expand Up @@ -280,10 +280,10 @@ ImpulseBinding *BindContext::bindImpulse(char const *ctrlDesc,
try
{
std::unique_ptr<ImpulseBinding> newBind(new ImpulseBinding);
inputSys().configure(*newBind, ctrlDesc, impulse.id, localPlayer); // Don't assign a new ID.
inputSys().configure(*newBind, ctrlDesc, impulse.id(), localPlayer); // Don't assign a new ID.

ImpulseBinding *bind = newBind.get();
ControlGroup &group = *d->findControlGroup(impulse.id, true/*create if missing*/);
ControlGroup &group = *d->findControlGroup(impulse.id(), true/*create if missing*/);
group.binds[localPlayer].append(newBind.release());

/// @todo: fix local player binding id management.
Expand All @@ -295,7 +295,7 @@ ImpulseBinding *BindContext::bindImpulse(char const *ctrlDesc,

LOG_INPUT_VERBOSE("Impulse " _E(b) "'%s'" _E(.) " of player%i now bound to \"%s\" in " _E(b) "'%s'" _E(.)
" with binding Id " _E(b) "%i")
<< impulse.name << (localPlayer + 1) << ctrlDesc << d->name << bind->id;
<< impulse.name() << (localPlayer + 1) << ctrlDesc << d->name << bind->id;

/// @todo: Notify interested parties.
//DENG2_FOR_AUDIENCE2(BindingAddition, i) i->bindContextBindingAdded(*this, bind, false/*is-impulse*/);
Expand Down
10 changes: 5 additions & 5 deletions doomsday/client/src/ui/inputsystem.cpp
Expand Up @@ -1404,7 +1404,7 @@ ImpulseBinding *InputSystem::bindImpulse(char const *ctrlDesc, char const *impul
return nullptr;
}

BindContext *context = contextPtr(impulse->bindContextName);
BindContext *context = contextPtr(impulse->bindContextName());
DENG2_ASSERT(context); // Should be known by now?
if(!context)
{
Expand Down Expand Up @@ -1893,11 +1893,11 @@ D_CMD(ListBindings)
for(int pl = 0; pl < DDMAXPLAYERS; ++pl)
context.forAllImpulseBindings(pl, [&isys, &pl] (ImpulseBinding &bind)
{
PlayerImpulse const *impulse = P_ImpulseById(bind.impulseId);
PlayerImpulse const *impulse = P_ImpulsePtr(bind.impulseId);
DENG2_ASSERT(impulse);

LOG_INPUT_MSG(" [%3i] " _E(>) _E(b) "%s" _E(.) " player%i %s")
<< bind.id << isys.composeBindsFor(bind) << (pl + 1) << impulse->name;
<< bind.id << isys.composeBindsFor(bind) << (pl + 1) << impulse->name();

return LoopContinue;
});
Expand Down Expand Up @@ -2048,10 +2048,10 @@ DENG_EXTERN_C int B_BindingsForControl(int localPlayer, char const *impulseNameC
{
DENG2_ASSERT(bind.localPlayer == localPlayer);

PlayerImpulse const *impulse = P_ImpulseById(bind.impulseId);
PlayerImpulse const *impulse = P_ImpulsePtr(bind.impulseId);
DENG2_ASSERT(impulse);

if(!impulse->name.compareWithoutCase(impulseName))
if(!impulse->name().compareWithoutCase(impulseName))
{
if(inverse == BFCI_BOTH ||
(inverse == BFCI_ONLY_NON_INVERSE && !(bind.flags & IBDF_INVERSE)) ||
Expand Down

0 comments on commit d46165f

Please sign in to comment.