mirror of
https://github.com/XProger/OpenLara.git
synced 2025-09-09 20:50:53 +02:00
#15 gamepad vibration on damage or earthquake; #11 gamepad index and some controls settings selector
This commit is contained in:
14
src/camera.h
14
src/camera.h
@@ -446,8 +446,10 @@ struct Camera : ICamera {
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
if (shake > 0.0f)
|
||||
if (shake > 0.0f) {
|
||||
shake = max(0.0f, shake - Core::deltaTime);
|
||||
osJoyVibrate(Core::settings.controls[cameraIndex].joyIndex, clamp(shake, 0.0f, 1.0f), 0);
|
||||
}
|
||||
|
||||
if (mode == MODE_CUTSCENE) {
|
||||
timer += Core::deltaTime * 30.0f;
|
||||
@@ -521,13 +523,13 @@ struct Camera : ICamera {
|
||||
if (Input::state[cameraIndex][cLook]) {
|
||||
float d = 2.0f * Core::deltaTime;
|
||||
|
||||
advAngle.x -= Input::joy[cameraIndex].L.y * d;
|
||||
advAngle.x += Input::joy[cameraIndex].L.y * d;
|
||||
advAngle.y += Input::joy[cameraIndex].L.x * d;
|
||||
|
||||
if (Input::state[cameraIndex][cUp]) advAngle.y += d;
|
||||
if (Input::state[cameraIndex][cDown]) advAngle.y -= d;
|
||||
if (Input::state[cameraIndex][cLeft]) advAngle.x += d;
|
||||
if (Input::state[cameraIndex][cRight]) advAngle.x -= d;
|
||||
if (Input::state[cameraIndex][cUp]) advAngle.x -= d;
|
||||
if (Input::state[cameraIndex][cDown]) advAngle.x += d;
|
||||
if (Input::state[cameraIndex][cLeft]) advAngle.y += d;
|
||||
if (Input::state[cameraIndex][cRight]) advAngle.y -= d;
|
||||
}
|
||||
|
||||
if (advAngleOld == advAngle) {
|
||||
|
@@ -77,6 +77,7 @@ struct IGame {
|
||||
virtual void setEffect(Controller *controller, TR::Effect::Type effect) {}
|
||||
|
||||
virtual void checkTrigger(Controller *controller, bool heavy) {}
|
||||
virtual void shakeCamera(float value, bool add = false) {}
|
||||
|
||||
virtual Controller* addEntity(TR::Entity::Type type, int room, const vec3 &pos, float angle = 0.0f) { return NULL; }
|
||||
virtual void removeEntity(Controller *controller) {}
|
||||
|
41
src/core.h
41
src/core.h
@@ -167,6 +167,9 @@
|
||||
extern int osGetTime();
|
||||
extern bool osSave(const char *name, const void *data, int size);
|
||||
|
||||
extern bool osJoyReady(int index);
|
||||
extern void osJoyVibrate(int index, float L, float R);
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
extern void* osMutexInit ();
|
||||
@@ -243,7 +246,7 @@ enum InputKey { ikNone,
|
||||
|
||||
enum JoyKey {
|
||||
// gamepad
|
||||
jkNone, jkA, jkB, jkX, jkY, jkLB, jkRB, jkSelect, jkStart, jkL, jkR, jkLT, jkRT, jkPOV, jkLeft, jkRight, jkUp, jkDown, jkMAX
|
||||
jkNone, jkA, jkB, jkX, jkY, jkLB, jkRB, jkSelect, jkStart, jkL, jkR, jkLT, jkRT, jkLeft, jkRight, jkUp, jkDown, jkMAX
|
||||
};
|
||||
|
||||
enum ControlKey {
|
||||
@@ -325,19 +328,19 @@ namespace Core {
|
||||
}
|
||||
} detail;
|
||||
|
||||
struct Controls {
|
||||
KeySet keys[cMAX];
|
||||
uint8 joyIndex;
|
||||
uint8 retarget;
|
||||
uint8 multitarget;
|
||||
uint8 vibration;
|
||||
} controls[2];
|
||||
|
||||
struct {
|
||||
uint8 music;
|
||||
uint8 sound;
|
||||
uint8 reverb;
|
||||
} audio;
|
||||
|
||||
struct Controls {
|
||||
uint8 joyIndex;
|
||||
uint8 vibration;
|
||||
uint8 retarget;
|
||||
uint8 multiaim;
|
||||
KeySet keys[cMAX];
|
||||
} controls[2];
|
||||
} settings;
|
||||
|
||||
bool resetState;
|
||||
@@ -1028,11 +1031,11 @@ namespace Core {
|
||||
|
||||
// player 1
|
||||
{
|
||||
Settings::Controls &ctrl = settings.controls[0];
|
||||
ctrl.retarget = true;
|
||||
ctrl.multitarget = true;
|
||||
ctrl.vibration = true;
|
||||
ctrl.joyIndex = 0;
|
||||
Settings::Controls &ctrl = settings.controls[0];
|
||||
ctrl.joyIndex = 0;
|
||||
ctrl.vibration = true;
|
||||
ctrl.retarget = true;
|
||||
ctrl.multiaim = true;
|
||||
|
||||
ctrl.keys[ cLeft ] = KeySet( ikLeft, jkLeft );
|
||||
ctrl.keys[ cRight ] = KeySet( ikRight, jkRight );
|
||||
@@ -1052,11 +1055,11 @@ namespace Core {
|
||||
|
||||
// player 2
|
||||
{
|
||||
Settings::Controls &ctrl = settings.controls[1];
|
||||
ctrl.retarget = true;
|
||||
ctrl.multitarget = true;
|
||||
ctrl.vibration = true;
|
||||
ctrl.joyIndex = 1;
|
||||
Settings::Controls &ctrl = settings.controls[1];
|
||||
ctrl.joyIndex = 1;
|
||||
ctrl.vibration = true;
|
||||
ctrl.retarget = true;
|
||||
ctrl.multiaim = true;
|
||||
|
||||
ctrl.keys[ cLeft ] = KeySet( ikNone, jkLeft );
|
||||
ctrl.keys[ cRight ] = KeySet( ikNone, jkRight );
|
||||
|
@@ -1173,7 +1173,7 @@ struct GiantMutant : Enemy {
|
||||
case STATE_FALL :
|
||||
if (stand == STAND_GROUND) {
|
||||
animation.setState(STATE_STOP);
|
||||
game->getCamera()->shake = 5.0f;
|
||||
game->shakeCamera(5.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1335,7 +1335,7 @@ struct ScionTarget : Enemy {
|
||||
if (index != int(timer / 0.3f)) {
|
||||
vec3 p = pos + vec3((randf() * 2.0f - 1.0f) * 512.0f, (randf() * 2.0f - 1.0f) * 64.0f - 500.0f, (randf() * 2.0f - 1.0f) * 512.0f);
|
||||
game->addEntity(TR::Entity::EXPLOSION, getRoomIndex(), p);
|
||||
game->getCamera()->shake = 0.5f;
|
||||
game->shakeCamera(0.5f);
|
||||
}
|
||||
|
||||
if (timer < 0.0f)
|
||||
|
38
src/input.h
38
src/input.h
@@ -4,6 +4,8 @@
|
||||
#include "core.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define INPUT_JOY_COUNT 4
|
||||
|
||||
namespace Input {
|
||||
|
||||
bool down[ikMAX];
|
||||
@@ -19,9 +21,8 @@ namespace Input {
|
||||
struct Joystick {
|
||||
vec2 L, R;
|
||||
float LT, RT;
|
||||
int POV;
|
||||
bool down[jkMAX];
|
||||
} joy[2];
|
||||
} joy[INPUT_JOY_COUNT];
|
||||
|
||||
struct Touch {
|
||||
int id;
|
||||
@@ -103,10 +104,9 @@ namespace Input {
|
||||
case jkR : joy[index].R = pos; return;
|
||||
case jkLT : joy[index].LT = pos.x; break;
|
||||
case jkRT : joy[index].RT = pos.x; break;
|
||||
case jkPOV : joy[index].POV = (int)pos.x; break;
|
||||
default : return;
|
||||
}
|
||||
setJoyDown(index, key, pos.x > 0.0f); // gamepad LT, RT, POV auto-down state
|
||||
setJoyDown(index, key, pos.x > 0.0f); // gamepad LT, RT auto-down state
|
||||
}
|
||||
|
||||
InputKey getTouch(int id) {
|
||||
@@ -164,18 +164,7 @@ namespace Input {
|
||||
dir = delta;
|
||||
}
|
||||
|
||||
void updateJoyPOV(int index) {
|
||||
int p = joy[index].POV;
|
||||
setJoyDown(index, jkUp, p == 8 || p == 1 || p == 2);
|
||||
setJoyDown(index, jkRight, p == 2 || p == 3 || p == 4);
|
||||
setJoyDown(index, jkDown, p == 4 || p == 5 || p == 6);
|
||||
setJoyDown(index, jkLeft, p == 6 || p == 7 || p == 8);
|
||||
}
|
||||
|
||||
void update() {
|
||||
updateJoyPOV(0);
|
||||
updateJoyPOV(1);
|
||||
|
||||
for (int j = 0; j < COUNT(Core::settings.controls); j++) {
|
||||
Core::Settings::Controls &ctrl = Core::settings.controls[j];
|
||||
for (int i = 0; i < cMAX; i++) {
|
||||
@@ -207,11 +196,15 @@ namespace Input {
|
||||
btnPos[bInventory] = vec2(Core::width - btnRadius * 2.0f, btnRadius * 2.0f);
|
||||
|
||||
// touch update
|
||||
if (checkTouchZone(zMove))
|
||||
joy[0].L = vec2(0.0f);
|
||||
Joystick &joy = Input::joy[Core::settings.controls[0].joyIndex];
|
||||
|
||||
if (checkTouchZone(zLook))
|
||||
joy[0].R = vec2(0.0f);
|
||||
if (checkTouchZone(zMove))
|
||||
joy.L = vec2(0.0f);
|
||||
|
||||
if (checkTouchZone(zLook)) {
|
||||
joy.L = vec2(0.0f);
|
||||
state[0][cLook] = false;
|
||||
}
|
||||
|
||||
if (checkTouchZone(zButton))
|
||||
btn = bNone;
|
||||
@@ -239,12 +232,15 @@ namespace Input {
|
||||
} else
|
||||
touchTimerTap = 0.3f;
|
||||
}
|
||||
|
||||
if (zone == zLook)
|
||||
state[0][cLook] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// set active touches as gamepad controls
|
||||
getTouchDir(touchKey[zMove], joy[0].L);
|
||||
getTouchDir(touchKey[zLook], joy[0].R);
|
||||
getTouchDir(touchKey[zMove], joy.L);
|
||||
getTouchDir(touchKey[zLook], joy.R);
|
||||
|
||||
if (touchKey[zButton] != ikNone) {
|
||||
vec2 pos = touch[touchKey[zButton] - ikTouchA].pos;
|
||||
|
@@ -112,6 +112,15 @@ static const OptionItem optSound[] = {
|
||||
OptionItem( OptionItem::TYPE_PARAM, STR_REVERBERATION, SETTINGS( audio.reverb ), STR_OFF, 0, 1 ),
|
||||
};
|
||||
|
||||
static OptionItem optControls[] = {
|
||||
OptionItem( OptionItem::TYPE_TITLE, STR_SELECT_LEVEL ),
|
||||
OptionItem( ),
|
||||
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_GAMEPAD, SETTINGS( controls[0].joyIndex ), STR_GAMEPAD_1, 0, 3 ),
|
||||
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_VIBRATION, SETTINGS( controls[0].vibration ), STR_OFF, 0, 1 ),
|
||||
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET, SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ),
|
||||
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM, SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ),
|
||||
};
|
||||
|
||||
static OptionItem optPassport[] = {
|
||||
OptionItem( OptionItem::TYPE_TITLE, STR_SELECT_LEVEL ),
|
||||
OptionItem( ),
|
||||
@@ -241,7 +250,7 @@ struct Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
const OptionItem* getOptions(int &optCount) {
|
||||
const OptionItem* getOptions(int &optCount) const {
|
||||
switch (type) {
|
||||
case TR::Entity::INV_PASSPORT :
|
||||
if (value != 0) return NULL;
|
||||
@@ -253,12 +262,19 @@ struct Inventory {
|
||||
case TR::Entity::INV_SOUND :
|
||||
optCount = COUNT(optSound);
|
||||
return optSound;
|
||||
case TR::Entity::INV_CONTROLS :
|
||||
optCount = COUNT(optControls);
|
||||
return optControls;
|
||||
default :
|
||||
optCount = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Core::Settings& getSettings(Inventory *inv) const {
|
||||
return (type == TR::Entity::INV_SOUND || type == TR::Entity::INV_CONTROLS) ? Core::settings : inv->settings;
|
||||
}
|
||||
|
||||
void nextSlot(int &slot, int dir) {
|
||||
int optCount;
|
||||
const OptionItem *options = getOptions(optCount);
|
||||
@@ -731,7 +747,7 @@ struct Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
Core::Settings &stg = item->type == TR::Entity::INV_SOUND ? Core::settings : settings;
|
||||
Core::Settings &stg = item->getSettings(this);
|
||||
|
||||
const OptionItem *opt = item->control(slot, key, changeTimer, &stg);
|
||||
if (opt)
|
||||
@@ -803,7 +819,7 @@ struct Inventory {
|
||||
|
||||
bool ready = active && phaseRing == 1.0f && phasePage == 1.0f;
|
||||
|
||||
Input::Joystick &joy = Input::joy[playerIndex];
|
||||
Input::Joystick &joy = Input::joy[Core::settings.controls[playerIndex].joyIndex];
|
||||
|
||||
ControlKey key = cMAX;
|
||||
if (Input::state[playerIndex][cAction])
|
||||
@@ -1056,7 +1072,7 @@ struct Inventory {
|
||||
x += 8.0f;
|
||||
width -= 16.0f;
|
||||
|
||||
Core::Settings &stg = item->type == TR::Entity::INV_SOUND ? Core::settings : settings;
|
||||
Core::Settings &stg = item->getSettings(this);
|
||||
for (int i = 0; i < optionsCount; i++)
|
||||
y = options[i].render(x, y, width, slot == i, &stg);
|
||||
}
|
||||
@@ -1076,19 +1092,15 @@ struct Inventory {
|
||||
case TR::Entity::INV_PASSPORT :
|
||||
renderPassport(item);
|
||||
break;
|
||||
case TR::Entity::INV_HOME :
|
||||
case TR::Entity::INV_DETAIL :
|
||||
case TR::Entity::INV_SOUND :
|
||||
case TR::Entity::INV_CONTROLS :
|
||||
renderOptions(item);
|
||||
break;
|
||||
case TR::Entity::INV_GAMMA :
|
||||
case TR::Entity::INV_COMPASS :
|
||||
case TR::Entity::INV_STOPWATCH :
|
||||
case TR::Entity::INV_MAP :
|
||||
break;
|
||||
case TR::Entity::INV_DETAIL :
|
||||
renderOptions(item);
|
||||
break;
|
||||
case TR::Entity::INV_SOUND :
|
||||
renderOptions(item);
|
||||
break;
|
||||
case TR::Entity::INV_CONTROLS :
|
||||
case TR::Entity::INV_GAMMA :
|
||||
case TR::Entity::INV_MAP :
|
||||
UI::textOut(vec2(-eye, 240), STR_NOT_IMPLEMENTED, UI::aCenter, UI::width);
|
||||
break;
|
||||
default : ;
|
||||
|
16
src/lara.h
16
src/lara.h
@@ -252,6 +252,8 @@ struct Lara : Character {
|
||||
|
||||
Camera *camera;
|
||||
|
||||
float hitTimer;
|
||||
|
||||
#ifdef _DEBUG
|
||||
//uint16 *dbgBoxes;
|
||||
//int dbgBoxesCount;
|
||||
@@ -429,6 +431,8 @@ struct Lara : Character {
|
||||
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), braid(NULL) {
|
||||
camera = new Camera(game, this);
|
||||
|
||||
hitTimer = 0.0f;
|
||||
|
||||
if (level->extra.laraSkin > -1)
|
||||
level->entities[entity].modelIndex = level->extra.laraSkin + 1;
|
||||
|
||||
@@ -1484,6 +1488,8 @@ struct Lara : Character {
|
||||
|
||||
Character::hit(damage, enemy, hitType);
|
||||
|
||||
hitTimer = 0.2f;
|
||||
|
||||
switch (hitType) {
|
||||
case TR::HIT_DART : addBlood(enemy->pos, vec3(0));
|
||||
case TR::HIT_BLADE : addBloodBlade(); break;
|
||||
@@ -2649,7 +2655,7 @@ struct Lara : Character {
|
||||
if (input & LOOK)
|
||||
return input;
|
||||
|
||||
Input::Joystick &joy = Input::joy[pid];
|
||||
Input::Joystick &joy = Input::joy[Core::settings.controls[pid].joyIndex];
|
||||
|
||||
if ((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(joy.L.x) < 0.5f && fabsf(joy.L.y) < 0.5f)
|
||||
return input;
|
||||
@@ -2740,6 +2746,14 @@ struct Lara : Character {
|
||||
|
||||
camera->update();
|
||||
|
||||
if (hitTimer > 0.0f) {
|
||||
hitTimer -= Core::deltaTime;
|
||||
if (hitTimer > 0.0f)
|
||||
osJoyVibrate(Core::settings.controls[camera->cameraIndex].joyIndex, 0.5f, 0.5f);
|
||||
else
|
||||
osJoyVibrate(Core::settings.controls[camera->cameraIndex].joyIndex, 0, 0);
|
||||
}
|
||||
|
||||
if (level->isCutsceneLevel())
|
||||
return;
|
||||
|
||||
|
25
src/level.h
25
src/level.h
@@ -393,7 +393,9 @@ struct Level : IGame {
|
||||
|
||||
switch (effect) {
|
||||
case TR::Effect::FLOOR_SHAKE :
|
||||
camera->shake = 0.5f * max(0.0f, 1.0f - (controller->pos - camera->eye.pos).length2() / (15 * 1024 * 15 * 1024));
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (players[i] && players[i]->camera)
|
||||
players[i]->camera->shake = 0.5f * max(0.0f, 1.0f - (controller->pos - players[i]->camera->eye.pos).length2() / (15 * 1024 * 15 * 1024));
|
||||
return;
|
||||
case TR::Effect::FLOOD : {
|
||||
Sound::Sample *sample = playSound(TR::SND_FLOOD, vec3(), 0);
|
||||
@@ -406,7 +408,7 @@ struct Level : IGame {
|
||||
break;
|
||||
case TR::Effect::EXPLOSION :
|
||||
playSound(TR::SND_TNT, vec3(0), 0);
|
||||
camera->shake = 1.0f;
|
||||
shakeCamera(1.0f);
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
@@ -416,6 +418,17 @@ struct Level : IGame {
|
||||
players[0]->checkTrigger(controller, heavy);
|
||||
}
|
||||
|
||||
virtual void shakeCamera(float value, bool add = false) {
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (players[i] && players[i]->camera) {
|
||||
if (add)
|
||||
players[i]->camera->shake += value;
|
||||
else
|
||||
players[i]->camera->shake = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual Controller* addEntity(TR::Entity::Type type, int room, const vec3 &pos, float angle) {
|
||||
int index;
|
||||
for (index = level.entitiesBaseCount; index < level.entitiesCount; index++) {
|
||||
@@ -1474,12 +1487,12 @@ struct Level : IGame {
|
||||
}
|
||||
case TR::Effect::EARTHQUAKE : {
|
||||
switch (effectIdx) {
|
||||
case 0 : if (effectTimer > 0.0f) { playSound(TR::SND_ROCK); effectIdx++; camera->shake = 1.0f; } break;
|
||||
case 0 : if (effectTimer > 0.0f) { playSound(TR::SND_ROCK); effectIdx++; shakeCamera(1.0f); } break;
|
||||
case 1 : if (effectTimer > 0.1f) { playSound(TR::SND_STOMP); effectIdx++; } break;
|
||||
case 2 : if (effectTimer > 0.6f) { playSound(TR::SND_BOULDER); effectIdx++; camera->shake += 0.5f; } break;
|
||||
case 2 : if (effectTimer > 0.6f) { playSound(TR::SND_BOULDER); effectIdx++; shakeCamera(0.5f, true); } break;
|
||||
case 3 : if (effectTimer > 1.1f) { playSound(TR::SND_ROCK); effectIdx++; } break;
|
||||
case 4 : if (effectTimer > 1.6f) { playSound(TR::SND_BOULDER); effectIdx++; camera->shake += 0.5f; } break;
|
||||
case 5 : if (effectTimer > 2.3f) { playSound(TR::SND_BOULDER); camera->shake += 0.5f; effect = TR::Effect::NONE; } break;
|
||||
case 4 : if (effectTimer > 1.6f) { playSound(TR::SND_BOULDER); effectIdx++; shakeCamera(0.5f, true); } break;
|
||||
case 5 : if (effectTimer > 2.3f) { playSound(TR::SND_BOULDER); shakeCamera(0.5f, true); effect = TR::Effect::NONE; } break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -173,52 +173,46 @@ DWORD (WINAPI *XInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||
|
||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||
#define JOY_MAX_COUNT 2
|
||||
#define JOY_NONE 255
|
||||
|
||||
uint8 joyIndex[JOY_MAX_COUNT];
|
||||
bool joyReady[INPUT_JOY_COUNT];
|
||||
|
||||
bool osJoyReady(int index) {
|
||||
return joyReady[index];
|
||||
}
|
||||
|
||||
void osJoyVibrate(int index, float L, float R) {
|
||||
if (XInputSetState && joyIndex[index] != JOY_NONE) {
|
||||
if (XInputSetState && joyReady[index]) {
|
||||
XINPUT_VIBRATION vibration;
|
||||
vibration.wLeftMotorSpeed = int(L * 65535.0f);
|
||||
vibration.wRightMotorSpeed = int(R * 65535.0f);
|
||||
XInputSetState(joyIndex[index], &vibration);
|
||||
XInputSetState(index, &vibration);
|
||||
}
|
||||
}
|
||||
|
||||
void joyInit() {
|
||||
memset(joyIndex, JOY_NONE, sizeof(joyIndex));
|
||||
int index = 0;
|
||||
memset(joyReady, 0, sizeof(joyReady));
|
||||
|
||||
HMODULE h = LoadLibrary("xinput9_1_0.dll");
|
||||
HMODULE h = LoadLibrary("xinput1_3.dll");
|
||||
|
||||
XInputGetState = (decltype(XInputGetState))GetProcAddress(h, "XInputGetState");
|
||||
XInputSetState = (decltype(XInputSetState))GetProcAddress(h, "XInputSetState");
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < INPUT_JOY_COUNT; j++) {
|
||||
if (XInputGetState) { // XInput
|
||||
XINPUT_STATE state;
|
||||
if (XInputGetState(j, &state) == ERROR_SUCCESS)
|
||||
joyIndex[index] = j;
|
||||
int res = XInputGetState(j, &state);
|
||||
joyReady[j] = (XInputGetState(j, &state) == ERROR_SUCCESS);
|
||||
} else { // mmSystem (legacy)
|
||||
JOYINFOEX info;
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
if (joyGetPosEx(j, &info) == JOYERR_NOERROR)
|
||||
joyIndex[index] = j;
|
||||
}
|
||||
|
||||
if (joyIndex[index] != JOY_NONE) {
|
||||
index++;
|
||||
if (index >= JOY_MAX_COUNT)
|
||||
break;
|
||||
joyReady[j] = (joyGetPosEx(j, &info) == JOYERR_NOERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void joyFree() {
|
||||
memset(joyIndex, JOY_NONE, sizeof(joyIndex));
|
||||
memset(joyReady, 0, sizeof(joyReady));
|
||||
Input::reset();
|
||||
}
|
||||
|
||||
@@ -253,14 +247,13 @@ int joyDeadZone(int value, int zone) {
|
||||
}
|
||||
|
||||
void joyUpdate() {
|
||||
for (int j = 0; j < JOY_MAX_COUNT; j++) {
|
||||
if (joyIndex[j] == JOY_NONE) break;
|
||||
int index = joyIndex[j];
|
||||
for (int j = 0; j < INPUT_JOY_COUNT; j++) {
|
||||
if (!joyReady[j]) continue;
|
||||
|
||||
if (XInputGetState) { // XInput
|
||||
XINPUT_STATE state;
|
||||
if (XInputGetState(index, &state) == ERROR_SUCCESS) {
|
||||
// osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
|
||||
if (XInputGetState(j, &state) == ERROR_SUCCESS) {
|
||||
//osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
|
||||
|
||||
Input::setJoyPos(j, jkL, joyDir(joyAxis(joyDeadZone( state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767),
|
||||
joyAxis(joyDeadZone(-state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767)));
|
||||
@@ -268,10 +261,9 @@ void joyUpdate() {
|
||||
joyAxis(joyDeadZone(-state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), -32768, 32767)));
|
||||
Input::setJoyPos(j, jkLT, vec2(joyDeadZone(state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||
Input::setJoyPos(j, jkRT, vec2(joyDeadZone(state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||
Input::setJoyPos(j, jkPOV, vec2(joyGetPOV(state.Gamepad.wButtons & 15), 0));
|
||||
|
||||
static const JoyKey keys[] = { jkUp, jkDown, jkLeft, jkRight, jkStart, jkSelect, jkL, jkR, jkLB, jkRB, jkNone, jkNone, jkA, jkB, jkX, jkY };
|
||||
for (int i = 4; i < 16; i++)
|
||||
for (int i = 0; i < 16; i++)
|
||||
Input::setJoyDown(j, keys[i], (state.Gamepad.wButtons & (1 << i)) != 0);
|
||||
} else {
|
||||
joyFree();
|
||||
@@ -283,37 +275,37 @@ void joyUpdate() {
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
|
||||
if (joyGetPosEx(index, &info) == JOYERR_NOERROR) {
|
||||
if (joyGetPosEx(j, &info) == JOYERR_NOERROR) {
|
||||
JOYCAPS caps;
|
||||
joyGetDevCaps(index, &caps, sizeof(caps));
|
||||
joyGetDevCaps(j, &caps, sizeof(caps));
|
||||
|
||||
if (caps.wNumAxes > 0) {
|
||||
Input::setJoyPos(index, jkL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax),
|
||||
Input::setJoyPos(j, jkL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax),
|
||||
joyAxis(info.dwYpos, caps.wYmin, caps.wYmax)));
|
||||
|
||||
if ((caps.wCaps & JOYCAPS_HASR) && (caps.wCaps & JOYCAPS_HASU))
|
||||
Input::setJoyPos(index, jkR, joyDir(joyAxis(info.dwUpos, caps.wUmin, caps.wUmax),
|
||||
Input::setJoyPos(j, jkR, joyDir(joyAxis(info.dwUpos, caps.wUmin, caps.wUmax),
|
||||
joyAxis(info.dwRpos, caps.wRmin, caps.wRmax)));
|
||||
|
||||
if (caps.wCaps & JOYCAPS_HASZ) {
|
||||
float z = joyAxis(info.dwZpos, caps.wZmin, caps.wZmax);
|
||||
Input::setJoyPos(index, jkLT, vec2(0.0f));
|
||||
Input::setJoyPos(index, jkRT, vec2(0.0f));
|
||||
Input::setJoyPos(j, jkLT, vec2(0.0f));
|
||||
Input::setJoyPos(j, jkRT, vec2(0.0f));
|
||||
|
||||
JoyKey key = z > JOY_DEAD_ZONE_TRIGGER ? jkLT : (z < -JOY_DEAD_ZONE_TRIGGER ? jkRT : jkNone);
|
||||
if (key != jkNone)
|
||||
Input::setJoyPos(index, key, vec2(fabsf(z), 0.0f));
|
||||
Input::setJoyPos(j, key, vec2(fabsf(z), 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (caps.wCaps & JOYCAPS_HASPOV)
|
||||
if (info.dwPOV == JOY_POVCENTERED)
|
||||
Input::setJoyPos(index, jkPOV, vec2(0.0f));
|
||||
else
|
||||
Input::setJoyPos(index, jkPOV, vec2(float(1 + info.dwPOV / 4500), 0.0f));
|
||||
int p = ((caps.wCaps & JOYCAPS_HASPOV) && (info.dwPOV != JOY_POVCENTERED)) ? (1 + info.dwPOV / 4500) : 0;
|
||||
Input::setJoyDown(j, jkUp, p == 8 || p == 1 || p == 2);
|
||||
Input::setJoyDown(j, jkRight, p == 2 || p == 3 || p == 4);
|
||||
Input::setJoyDown(j, jkDown, p == 4 || p == 5 || p == 6);
|
||||
Input::setJoyDown(j, jkLeft, p == 6 || p == 7 || p == 8);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
Input::setJoyDown(index, JoyKey(jkA + i), (info.dwButtons & (1 << i)) > 0);
|
||||
Input::setJoyDown(j, JoyKey(jkA + i), (info.dwButtons & (1 << i)) > 0);
|
||||
} else {
|
||||
joyFree();
|
||||
joyInit();
|
||||
|
@@ -1362,10 +1362,10 @@ struct Earthquake : Controller {
|
||||
float p = randf();
|
||||
if (p < 0.001f) {
|
||||
game->playSound(TR::SND_STOMP);
|
||||
game->getCamera()->shake = 1.0f;
|
||||
game->shakeCamera(1.0f);
|
||||
} else if (p < 0.04f) {
|
||||
game->playSound(TR::SND_BOULDER);
|
||||
game->getCamera()->shake = 0.3f;
|
||||
game->shakeCamera(0.3f);
|
||||
}
|
||||
|
||||
timer = 0.0f;
|
||||
|
20
src/ui.h
20
src/ui.h
@@ -17,6 +17,11 @@ enum StringID {
|
||||
, STR_QUALITY_MEDIUM
|
||||
, STR_QUALITY_HIGH
|
||||
, STR_APPLY
|
||||
, STR_GAMEPAD_1
|
||||
, STR_GAMEPAD_2
|
||||
, STR_GAMEPAD_3
|
||||
, STR_GAMEPAD_4
|
||||
, STR_NOT_READY
|
||||
// inventory pages
|
||||
, STR_OPTION
|
||||
, STR_INVENTORY
|
||||
@@ -50,6 +55,11 @@ enum StringID {
|
||||
// sound options
|
||||
, STR_SET_VOLUMES
|
||||
, STR_REVERBERATION
|
||||
// controls options
|
||||
, STR_OPT_CONTROLS_GAMEPAD
|
||||
, STR_OPT_CONTROLS_VIBRATION
|
||||
, STR_OPT_CONTROLS_RETARGET
|
||||
, STR_OPT_CONTROLS_MULTIAIM
|
||||
// inventory items
|
||||
, STR_UNKNOWN
|
||||
, STR_PISTOLS
|
||||
@@ -111,6 +121,11 @@ const char *STR[STR_MAX] = {
|
||||
, "Medium"
|
||||
, "High"
|
||||
, "Apply"
|
||||
, "Gamepad 1"
|
||||
, "Gamepad 2"
|
||||
, "Gamepad 3"
|
||||
, "Gamepad 4"
|
||||
, "Not Ready"
|
||||
// inventory pages
|
||||
, "OPTION"
|
||||
, "INVENTORY"
|
||||
@@ -144,6 +159,11 @@ const char *STR[STR_MAX] = {
|
||||
// sound options
|
||||
, "Set Volumes"
|
||||
, "Reverberation"
|
||||
// controls options
|
||||
, "Gamepad"
|
||||
, "Vibration"
|
||||
, "Retargeting"
|
||||
, "Multi-aiming"
|
||||
// inventory items
|
||||
, "Unknown"
|
||||
, "Pistols"
|
||||
|
Reference in New Issue
Block a user