1
0
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:
XProger
2018-02-22 07:06:13 +03:00
parent 0efa5aa90c
commit 77f205f976
11 changed files with 165 additions and 112 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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