Browse Source

Enhanced attack using controllers (#4019)

pull/4337/head
Felipe Wannmacher 4 years ago committed by GitHub
parent
commit
889cc04f95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      Source/controls/controller.cpp
  2. 11
      Source/controls/controller.h
  3. 10
      Source/controls/devices/game_controller.cpp
  4. 5
      Source/controls/devices/game_controller.h
  5. 2
      Source/controls/devices/joystick.h
  6. 18
      Source/controls/game_controls.cpp
  7. 2
      Source/controls/game_controls.h
  8. 7
      Source/controls/input.h
  9. 10
      Source/controls/plrctrls.cpp
  10. 2
      Source/controls/plrctrls.h

91
Source/controls/controller.cpp

@ -7,9 +7,54 @@
#endif
#include "controls/devices/joystick.h"
#include "controls/devices/kbcontroller.h"
#include "controls/game_controls.h"
#include "controls/plrctrls.h"
#include "player.h"
namespace devilution {
namespace {
bool skipTick = false;
bool heldControllerButtonEventsLocked = false;
ControllerButton actionButtons[2] = { ControllerButton_ATTACK, ControllerButton_CAST_SPELL };
bool CreateActionButtonEvent(SDL_Event *event, ControllerButton button)
{
SDL_JoystickID which;
#ifndef USE_SDL1
if (GameController::IsPressedOnAnyController(button, &which)) {
event->type = SDL_CONTROLLERBUTTONDOWN;
event->cbutton.button = GameController::ToSdlGameControllerButton(button);
event->cbutton.state = ControllerButtonState_HELD;
event->cbutton.which = which;
return true;
}
#endif
#if HAS_KBCTRL == 1
if (IsKbCtrlButtonPressed(button)) {
event->type = SDL_KEYDOWN;
event->key.keysym.sym = ControllerButtonToKbCtrlKeyCode(button);
event->key.state = ControllerButtonState_HELD;
return true;
}
#endif
if (Joystick::IsPressedOnAnyJoystick(button)) {
event->type = SDL_JOYBUTTONDOWN;
event->jbutton.button = Joystick::ToSdlJoyButton(button);
event->jbutton.state = ControllerButtonState_HELD;
return true;
}
return false;
}
} // namespace
void UnlockControllerState(const SDL_Event &event)
{
#ifndef USE_SDL1
@ -22,7 +67,7 @@ void UnlockControllerState(const SDL_Event &event)
ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event)
{
ControllerButtonEvent result { ControllerButton_NONE, false };
ControllerButtonEvent result { ControllerButton_NONE, false, ControllerButtonState_RELEASED };
switch (event.type) {
#ifndef USE_SDL1
case SDL_CONTROLLERBUTTONUP:
@ -36,6 +81,8 @@ ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event)
}
#if HAS_KBCTRL == 1
result.button = KbCtrlToControllerButton(event);
result.state = event.key.state;
if (result.button != ControllerButton_NONE)
return result;
#endif
@ -43,14 +90,18 @@ ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event)
GameController *const controller = GameController::Get(event);
if (controller != nullptr) {
result.button = controller->ToControllerButton(event);
result.state = event.cbutton.state;
if (result.button != ControllerButton_NONE)
return result;
}
#endif
const Joystick *joystick = Joystick::Get(event);
if (joystick != nullptr)
if (joystick != nullptr) {
result.button = devilution::Joystick::ToControllerButton(event);
result.state = event.jbutton.state;
}
return result;
}
@ -93,4 +144,40 @@ bool HandleControllerAddedOrRemovedEvent(const SDL_Event &event)
#endif
}
void UnlockHeldControllerButtonEvents(const SDL_Event &event)
{
ControllerButtonEvent ctrlEvent = ToControllerButtonEvent(event);
for (int i = 0; i < 2; ++i)
if (actionButtons[i] == ctrlEvent.button) {
heldControllerButtonEventsLocked = !CanControlHero();
break;
}
}
int PollActionButtonPressed(SDL_Event *event)
{
if (heldControllerButtonEventsLocked)
return 0;
if (skipTick) {
skipTick = false;
return 0;
}
if (!Players[MyPlayerId].CanChangeAction())
return 0;
for (int i = 0; i < 2; ++i)
if (CreateActionButtonEvent(event, actionButtons[i])) {
skipTick = true; // 1 tick is skipped for allowing the player animation to change
return 1;
}
return 0;
}
} // namespace devilution

11
Source/controls/controller.h

@ -6,9 +6,16 @@
namespace devilution {
enum ControllerButtonState : uint8_t {
ControllerButtonState_RELEASED = SDL_RELEASED,
ControllerButtonState_PRESSED = SDL_PRESSED,
ControllerButtonState_HELD = SDL_PRESSED + SDL_RELEASED + 1 // for making it sure that the value is different
};
struct ControllerButtonEvent {
ControllerButton button;
bool up;
uint8_t state;
};
// Must be called exactly once at the start of each SDL input event.
@ -20,4 +27,8 @@ bool IsControllerButtonPressed(ControllerButton button);
bool HandleControllerAddedOrRemovedEvent(const SDL_Event &event);
void UnlockHeldControllerButtonEvents(const SDL_Event &event);
int PollActionButtonPressed(SDL_Event *event);
} // namespace devilution

10
Source/controls/devices/game_controller.cpp

@ -205,7 +205,7 @@ GameController *GameController::Get(const SDL_Event &event)
return Get(event.caxis.which);
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
return Get(event.jball.which);
return Get(event.cbutton.which);
default:
return nullptr;
}
@ -216,11 +216,15 @@ const std::vector<GameController> &GameController::All()
return controllers_;
}
bool GameController::IsPressedOnAnyController(ControllerButton button)
bool GameController::IsPressedOnAnyController(ControllerButton button, SDL_JoystickID *which)
{
for (auto &controller : controllers_)
if (controller.IsPressed(button))
if (controller.IsPressed(button)) {
if (which != nullptr)
*which = controller.instance_id_;
return true;
}
return false;
}

5
Source/controls/devices/game_controller.h

@ -17,7 +17,7 @@ public:
static GameController *Get(SDL_JoystickID instanceId);
static GameController *Get(const SDL_Event &event);
static const std::vector<GameController> &All();
static bool IsPressedOnAnyController(ControllerButton button);
static bool IsPressedOnAnyController(ControllerButton button, SDL_JoystickID *which = nullptr);
// Must be called exactly once at the start of each SDL input event.
void UnlockTriggerState();
@ -26,10 +26,9 @@ public:
bool IsPressed(ControllerButton button) const;
static bool ProcessAxisMotion(const SDL_Event &event);
private:
static SDL_GameControllerButton ToSdlGameControllerButton(ControllerButton button);
private:
SDL_GameController *sdl_game_controller_ = NULL;
SDL_JoystickID instance_id_ = -1;

2
Source/controls/devices/joystick.h

@ -34,9 +34,9 @@ public:
return instance_id_;
}
private:
static int ToSdlJoyButton(ControllerButton button);
private:
bool IsHatButtonPressed(ControllerButton button) const;
SDL_Joystick *sdl_joystick_ = NULL;

18
Source/controls/game_controls.cpp

@ -15,6 +15,7 @@
#include "doom.h"
#include "gmenu.h"
#include "options.h"
#include "plrctrls.h"
#include "qol/stash.h"
#include "stores.h"
@ -22,6 +23,8 @@ namespace devilution {
bool start_modifier_active = false;
bool select_modifier_active = false;
const ControllerButton ControllerButton_ATTACK = ControllerButton_BUTTON_B;
const ControllerButton ControllerButton_CAST_SPELL = ControllerButton_BUTTON_X;
namespace {
@ -194,6 +197,21 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, Game
break;
}
if (ctrlEvent.state == ControllerButtonState_HELD) {
if (CanControlHero() && !select_modifier_active && !start_modifier_active) {
switch (ctrlEvent.button) {
case ControllerButton_ATTACK:
*action = GameAction(GameActionType_PRIMARY_ACTION);
break;
case ControllerButton_CAST_SPELL:
*action = GameAction(GameActionType_CAST_SPELL);
break;
}
}
return true;
}
if (!inGameMenu) {
switch (ctrlEvent.button) {
case ControllerButton_BUTTON_LEFTSHOULDER:

2
Source/controls/game_controls.h

@ -75,5 +75,7 @@ AxisDirection GetMoveDirection();
extern bool start_modifier_active;
extern bool select_modifier_active;
extern const ControllerButton ControllerButton_ATTACK;
extern const ControllerButton ControllerButton_CAST_SPELL;
} // namespace devilution

7
Source/controls/input.h

@ -9,8 +9,13 @@ namespace devilution {
inline int PollEvent(SDL_Event *event)
{
int result = SDL_PollEvent(event);
if (result != 0)
if (result != 0) {
UnlockControllerState(*event);
UnlockHeldControllerButtonEvents(*event);
} else {
result = PollActionButtonPressed(event);
}
return result;
}

10
Source/controls/plrctrls.cpp

@ -61,6 +61,16 @@ bool InGameMenu()
|| Players[MyPlayerId]._pInvincible;
}
bool CanControlHero()
{
return !InGameMenu()
&& !invflag
&& !spselflag
&& !QuestLogIsOpen
&& !sbookflag
&& !DoomFlag;
}
namespace {
int Slot = SLOTXY_INV_FIRST;

2
Source/controls/plrctrls.h

@ -59,6 +59,8 @@ void HandleRightStickMotion();
// Whether we're in a dialog menu that the game handles natively with keyboard controls.
bool InGameMenu();
bool CanControlHero();
void SetPointAndClick(bool value);
bool IsPointAndClick();

Loading…
Cancel
Save