Add rumble when player fires portal gun
This commit is contained in:
parent
ed6dcd5948
commit
c18354ad76
|
@ -3,8 +3,8 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
#include "rumble_pak.h"
|
||||||
|
|
||||||
#include "../debugger/serial.h"
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// 0 = disable, 1 = record, 2 = playback
|
// 0 = disable, 1 = record, 2 = playback
|
||||||
|
@ -33,7 +33,6 @@ static u8 gControllerReadInProgress = 0;
|
||||||
static u8 gLastControllerQuery = ControllerEventTypeNone;
|
static u8 gLastControllerQuery = ControllerEventTypeNone;
|
||||||
static u8 gRumblePakState;
|
static u8 gRumblePakState;
|
||||||
static u8 gRumblePakOn;
|
static u8 gRumblePakOn;
|
||||||
static u8 gRumbleDelay;
|
|
||||||
|
|
||||||
static OSPfs gRumbleBackFs;
|
static OSPfs gRumbleBackFs;
|
||||||
|
|
||||||
|
@ -85,11 +84,13 @@ void controllersInit(void)
|
||||||
osSetEventMesg(OS_EVENT_SI, &gControllerMsgQ, (OSMesg)&gControllerMessage);
|
osSetEventMesg(OS_EVENT_SI, &gControllerMsgQ, (OSMesg)&gControllerMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
int controllerGetTargetRumbleStatus() {
|
void controllerQueryStatus() {
|
||||||
return 0;
|
osContStartQuery(&gControllerMsgQ);
|
||||||
|
gControllerReadInProgress = 1;
|
||||||
|
gLastControllerQuery = ControllerEventTypeStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
void controllerHandleMessage() {
|
int controllerHandleMessage() {
|
||||||
if (gLastControllerQuery == ControllerEventTypeData) {
|
if (gLastControllerQuery == ControllerEventTypeData) {
|
||||||
osContGetReadData(gControllerData);
|
osContGetReadData(gControllerData);
|
||||||
gControllerReadInProgress = 0;
|
gControllerReadInProgress = 0;
|
||||||
|
@ -105,14 +106,10 @@ void controllerHandleMessage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gRumblePakState != RumblepakStateInitialized) {
|
return TRUE;
|
||||||
osContStartQuery(&gControllerMsgQ);
|
|
||||||
gControllerReadInProgress = 1;
|
|
||||||
gLastControllerQuery = ControllerEventTypeStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (gLastControllerQuery == ControllerEventTypeStatus) {
|
} else if (gLastControllerQuery == ControllerEventTypeStatus) {
|
||||||
int prevStatus = gControllerStatus[0].status;
|
int prevStatus = gControllerStatus[0].status;
|
||||||
|
gControllerReadInProgress = 0;
|
||||||
|
|
||||||
osContGetQuery(&gControllerStatus[0]);
|
osContGetQuery(&gControllerStatus[0]);
|
||||||
gLastControllerQuery = ControllerEventTypeNone;
|
gLastControllerQuery = ControllerEventTypeNone;
|
||||||
|
@ -120,7 +117,6 @@ void controllerHandleMessage() {
|
||||||
if ((prevStatus != CONT_CARD_ON && gControllerStatus[0].status == CONT_CARD_ON && gRumblePakState == RumblepakStateDisconnected) || gRumblePakState == RumplepakStateUninitialized) {
|
if ((prevStatus != CONT_CARD_ON && gControllerStatus[0].status == CONT_CARD_ON && gRumblePakState == RumblepakStateDisconnected) || gRumblePakState == RumplepakStateUninitialized) {
|
||||||
if (osMotorInit(&gControllerMsgQ, &gRumbleBackFs, 0) == 0) {
|
if (osMotorInit(&gControllerMsgQ, &gRumbleBackFs, 0) == 0) {
|
||||||
gRumblePakState = RumblepakStateInitialized;
|
gRumblePakState = RumblepakStateInitialized;
|
||||||
gRumbleDelay = 16;
|
|
||||||
} else {
|
} else {
|
||||||
gRumblePakState = RumblepakStateDisconnected;
|
gRumblePakState = RumblepakStateDisconnected;
|
||||||
gRumblePakOn = 0;
|
gRumblePakOn = 0;
|
||||||
|
@ -130,37 +126,48 @@ void controllerHandleMessage() {
|
||||||
gRumblePakOn = 0;
|
gRumblePakOn = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void controllersReadPendingData(void) {
|
void controllersReadPendingData(void) {
|
||||||
OSMesg msg;
|
OSMesg msg;
|
||||||
|
int shouldCheckStatus;
|
||||||
|
|
||||||
if (osRecvMesg(&gControllerMsgQ, &msg, OS_MESG_NOBLOCK) != -1) {
|
if (osRecvMesg(&gControllerMsgQ, &msg, OS_MESG_NOBLOCK) != -1) {
|
||||||
controllerHandleMessage();
|
shouldCheckStatus = controllerHandleMessage();
|
||||||
|
} else {
|
||||||
|
shouldCheckStatus = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int targetRumbleStatus = rumblePakCalculateState();
|
||||||
|
|
||||||
if (gRumblePakState == RumblepakStateInitialized) {
|
if (gRumblePakState == RumblepakStateInitialized) {
|
||||||
int targetRumbleStatus = controllerGetTargetRumbleStatus();
|
|
||||||
|
|
||||||
if (gRumbleDelay > 0) {
|
|
||||||
--gRumbleDelay;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetRumbleStatus != gRumblePakOn) {
|
if (targetRumbleStatus != gRumblePakOn) {
|
||||||
|
shouldCheckStatus = FALSE;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
s32 rumbleError = targetRumbleStatus ? osMotorStart(&gRumbleBackFs) : osMotorStop(&gRumbleBackFs);
|
s32 rumbleError = targetRumbleStatus ? osMotorStart(&gRumbleBackFs) : osMotorStop(&gRumbleBackFs);
|
||||||
|
|
||||||
if (rumbleError == PFS_ERR_CONTRFAIL) {
|
if (rumbleError == PFS_ERR_CONTRFAIL) {
|
||||||
gRumblePakState = RumplepakStateUninitialized;
|
continue;
|
||||||
} else if (rumbleError != 0) {
|
} else if (rumbleError != 0) {
|
||||||
gRumblePakState = RumblepakStateDisconnected;
|
gRumblePakState = RumblepakStateDisconnected;
|
||||||
gRumblePakOn = 0;
|
gRumblePakOn = 0;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
gRumblePakOn = targetRumbleStatus;
|
gRumblePakOn = targetRumbleStatus;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldCheckStatus) {
|
||||||
|
controllerQueryStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void controllersSavePreviousState(void) {
|
void controllersSavePreviousState(void) {
|
||||||
for (unsigned i = 0; i < MAX_PLAYERS; ++i) {
|
for (unsigned i = 0; i < MAX_PLAYERS; ++i) {
|
||||||
gControllerLastDirection[i] = controllerGetDirection(i);
|
gControllerLastDirection[i] = controllerGetDirection(i);
|
||||||
|
|
152
src/controls/rumble_pak.c
Normal file
152
src/controls/rumble_pak.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#include "rumble_pak.h"
|
||||||
|
|
||||||
|
#include <ultra64.h>
|
||||||
|
#include "../util/time.h"
|
||||||
|
|
||||||
|
#define MAX_ACTIVE_RUMBLE 4
|
||||||
|
|
||||||
|
struct RumblePakClip gClips[MAX_ACTIVE_RUMBLE];
|
||||||
|
struct RumblePakClip* gFirstActiveClip = NULL;
|
||||||
|
struct RumblePakClip* gFirstIdleClip = NULL;
|
||||||
|
RumbleID gNextRumbleId = 1;
|
||||||
|
|
||||||
|
void rumblePakClipInit() {
|
||||||
|
struct RumblePakClip* prev = NULL;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_ACTIVE_RUMBLE; ++i) {
|
||||||
|
struct RumblePakClip* curr = &gClips[i];
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
prev->next = curr;
|
||||||
|
} else {
|
||||||
|
gFirstIdleClip = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->wave = NULL;
|
||||||
|
curr->currentSample = 0;
|
||||||
|
curr->rumbleId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RumbleID rumblePakClipPlay(struct RumblePakWave* wave) {
|
||||||
|
if (!gFirstIdleClip) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RumblePakClip* clip = gFirstIdleClip;
|
||||||
|
|
||||||
|
gFirstIdleClip = gFirstIdleClip->next;
|
||||||
|
|
||||||
|
clip->next = gFirstActiveClip;
|
||||||
|
gFirstActiveClip = clip;
|
||||||
|
clip->currentSample = 0;
|
||||||
|
clip->wave = wave;
|
||||||
|
clip->rumbleId = gNextRumbleId;
|
||||||
|
++gNextRumbleId;
|
||||||
|
|
||||||
|
return clip->rumbleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rumblePakClipIsActive(RumbleID clip) {
|
||||||
|
struct RumblePakClip* curr = gFirstActiveClip;
|
||||||
|
|
||||||
|
while (curr) {
|
||||||
|
if (curr->rumbleId == clip) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rumblePakClipStop(RumbleID clipId) {
|
||||||
|
struct RumblePakClip* clip = gFirstActiveClip;
|
||||||
|
|
||||||
|
while (clip) {
|
||||||
|
if (clip->rumbleId == clipId) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clip = clip->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RumblePakClip* curr = gFirstActiveClip;
|
||||||
|
struct RumblePakClip* prev = NULL;
|
||||||
|
|
||||||
|
while (curr) {
|
||||||
|
if (curr == clip) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = curr->next;
|
||||||
|
} else {
|
||||||
|
gFirstActiveClip = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->wave = NULL;
|
||||||
|
curr->next = NULL;
|
||||||
|
|
||||||
|
curr->next = gFirstIdleClip;
|
||||||
|
gFirstIdleClip = curr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int gRumbleCurrentBit = 0;
|
||||||
|
|
||||||
|
int rumblePakCalculateState() {
|
||||||
|
int amplitude = 0;
|
||||||
|
|
||||||
|
struct RumblePakClip* curr = gFirstActiveClip;
|
||||||
|
struct RumblePakClip* prev = NULL;
|
||||||
|
|
||||||
|
while (curr) {
|
||||||
|
int sampleAsInt = curr->currentSample >> 6;
|
||||||
|
|
||||||
|
if (sampleAsInt >= curr->wave->sampleCount) {
|
||||||
|
// clip is done, remove it
|
||||||
|
curr->wave = NULL;
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
prev->next = curr->next;
|
||||||
|
} else {
|
||||||
|
gFirstActiveClip = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RumblePakClip* next = curr->next;
|
||||||
|
curr->next = gFirstIdleClip;
|
||||||
|
gFirstIdleClip = curr;
|
||||||
|
curr = next;
|
||||||
|
} else {
|
||||||
|
int byteIndex = sampleAsInt >> 2;
|
||||||
|
int byteOffset = sampleAsInt & 0x3;
|
||||||
|
|
||||||
|
u8 byte = curr->wave->samples[byteIndex];
|
||||||
|
|
||||||
|
amplitude += (byte >> (6 - byteOffset * 2)) & 0x3;
|
||||||
|
|
||||||
|
curr->currentSample += curr->wave->samplesPerTick;
|
||||||
|
|
||||||
|
prev = curr;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amplitude > 3) {
|
||||||
|
amplitude = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = amplitude >= gRumbleCurrentBit;
|
||||||
|
gRumbleCurrentBit = (gRumbleCurrentBit + 1) & 0x3;
|
||||||
|
return result;
|
||||||
|
}
|
29
src/controls/rumble_pak.h
Normal file
29
src/controls/rumble_pak.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef __CONTROLS__RUMBLE_PAK_H__
|
||||||
|
#define __CONTROLS__RUMBLE_PAK_H__
|
||||||
|
|
||||||
|
struct RumblePakWave {
|
||||||
|
// 2 bits per sample
|
||||||
|
unsigned char* samples;
|
||||||
|
short sampleCount;
|
||||||
|
// 10.6 fixed point number ticks happens at 60 times per second (50 for pal)
|
||||||
|
short samplesPerTick;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef short RumbleID;
|
||||||
|
|
||||||
|
struct RumblePakClip {
|
||||||
|
struct RumblePakWave* wave;
|
||||||
|
struct RumblePakClip* next;
|
||||||
|
// 10.6 fixed point number
|
||||||
|
short currentSample;
|
||||||
|
RumbleID rumbleId;
|
||||||
|
};
|
||||||
|
|
||||||
|
void rumblePakClipInit();
|
||||||
|
RumbleID rumblePakClipPlay(struct RumblePakWave* wave);
|
||||||
|
int rumblePakClipIsActive(RumbleID clip);
|
||||||
|
void rumblePakClipStop(RumbleID clip);
|
||||||
|
|
||||||
|
int rumblePakCalculateState();
|
||||||
|
|
||||||
|
#endif
|
|
@ -31,6 +31,7 @@
|
||||||
#include "render_plan.h"
|
#include "render_plan.h"
|
||||||
#include "../menu/game_menu.h"
|
#include "../menu/game_menu.h"
|
||||||
#include "../effects/effect_definitions.h"
|
#include "../effects/effect_definitions.h"
|
||||||
|
#include "../controls/rumble_pak.h"
|
||||||
|
|
||||||
extern struct GameMenu gGameMenu;
|
extern struct GameMenu gGameMenu;
|
||||||
|
|
||||||
|
@ -321,7 +322,15 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 gFireGunRumbleWaveData[] = {
|
||||||
|
0xFF, 0xE9,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RumblePakWave gFireGunRumbleWave = {
|
||||||
|
.samples = gFireGunRumbleWaveData,
|
||||||
|
.sampleCount = 8,
|
||||||
|
.samplesPerTick = 1 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
void sceneCheckPortals(struct Scene* scene) {
|
void sceneCheckPortals(struct Scene* scene) {
|
||||||
if (playerIsDead(&scene->player)) {
|
if (playerIsDead(&scene->player)) {
|
||||||
|
@ -352,6 +361,7 @@ void sceneCheckPortals(struct Scene* scene) {
|
||||||
scene->player.flags |= PlayerJustShotPortalGun;
|
scene->player.flags |= PlayerJustShotPortalGun;
|
||||||
hudPortalFired(&scene->hud, 0);
|
hudPortalFired(&scene->hud, 0);
|
||||||
soundPlayerPlay(soundsPortalgunShoot[0], 1.0f, 1.0f, NULL, NULL);
|
soundPlayerPlay(soundsPortalgunShoot[0], 1.0f, 1.0f, NULL, NULL);
|
||||||
|
rumblePakClipPlay(&gFireGunRumbleWave);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((fireBlue && !fireOrange) || (!hasOrange && fireOrange)) && hasBlue && !playerIsGrabbing(&scene->player) && !portalGunIsFiring(&scene->portalGun)) {
|
if (((fireBlue && !fireOrange) || (!hasOrange && fireOrange)) && hasBlue && !playerIsGrabbing(&scene->player) && !portalGunIsFiring(&scene->portalGun)) {
|
||||||
|
@ -359,6 +369,7 @@ void sceneCheckPortals(struct Scene* scene) {
|
||||||
scene->player.flags |= PlayerJustShotPortalGun;
|
scene->player.flags |= PlayerJustShotPortalGun;
|
||||||
hudPortalFired(&scene->hud, 1);
|
hudPortalFired(&scene->hud, 1);
|
||||||
soundPlayerPlay(soundsPortalgunShoot[1], 1.0f, 1.0f, NULL, NULL);
|
soundPlayerPlay(soundsPortalgunShoot[1], 1.0f, 1.0f, NULL, NULL);
|
||||||
|
rumblePakClipPlay(&gFireGunRumbleWave);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fireOrange || fireBlue) && playerIsGrabbing(&scene->player)){
|
if ((fireOrange || fireBlue) && playerIsGrabbing(&scene->player)){
|
||||||
|
|
Loading…
Reference in a new issue