Add rumble when player fires portal gun
This commit is contained in:
parent
ed6dcd5948
commit
c18354ad76
|
@ -3,8 +3,8 @@
|
|||
#include "defs.h"
|
||||
#include "util/memory.h"
|
||||
#include <sched.h>
|
||||
#include "rumble_pak.h"
|
||||
|
||||
#include "../debugger/serial.h"
|
||||
#include <string.h>
|
||||
|
||||
// 0 = disable, 1 = record, 2 = playback
|
||||
|
@ -33,7 +33,6 @@ static u8 gControllerReadInProgress = 0;
|
|||
static u8 gLastControllerQuery = ControllerEventTypeNone;
|
||||
static u8 gRumblePakState;
|
||||
static u8 gRumblePakOn;
|
||||
static u8 gRumbleDelay;
|
||||
|
||||
static OSPfs gRumbleBackFs;
|
||||
|
||||
|
@ -85,11 +84,13 @@ void controllersInit(void)
|
|||
osSetEventMesg(OS_EVENT_SI, &gControllerMsgQ, (OSMesg)&gControllerMessage);
|
||||
}
|
||||
|
||||
int controllerGetTargetRumbleStatus() {
|
||||
return 0;
|
||||
void controllerQueryStatus() {
|
||||
osContStartQuery(&gControllerMsgQ);
|
||||
gControllerReadInProgress = 1;
|
||||
gLastControllerQuery = ControllerEventTypeStatus;
|
||||
}
|
||||
|
||||
void controllerHandleMessage() {
|
||||
int controllerHandleMessage() {
|
||||
if (gLastControllerQuery == ControllerEventTypeData) {
|
||||
osContGetReadData(gControllerData);
|
||||
gControllerReadInProgress = 0;
|
||||
|
@ -105,14 +106,10 @@ void controllerHandleMessage() {
|
|||
}
|
||||
}
|
||||
|
||||
if (gRumblePakState != RumblepakStateInitialized) {
|
||||
osContStartQuery(&gControllerMsgQ);
|
||||
gControllerReadInProgress = 1;
|
||||
gLastControllerQuery = ControllerEventTypeStatus;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else if (gLastControllerQuery == ControllerEventTypeStatus) {
|
||||
int prevStatus = gControllerStatus[0].status;
|
||||
gControllerReadInProgress = 0;
|
||||
|
||||
osContGetQuery(&gControllerStatus[0]);
|
||||
gLastControllerQuery = ControllerEventTypeNone;
|
||||
|
@ -120,7 +117,6 @@ void controllerHandleMessage() {
|
|||
if ((prevStatus != CONT_CARD_ON && gControllerStatus[0].status == CONT_CARD_ON && gRumblePakState == RumblepakStateDisconnected) || gRumblePakState == RumplepakStateUninitialized) {
|
||||
if (osMotorInit(&gControllerMsgQ, &gRumbleBackFs, 0) == 0) {
|
||||
gRumblePakState = RumblepakStateInitialized;
|
||||
gRumbleDelay = 16;
|
||||
} else {
|
||||
gRumblePakState = RumblepakStateDisconnected;
|
||||
gRumblePakOn = 0;
|
||||
|
@ -130,37 +126,48 @@ void controllerHandleMessage() {
|
|||
gRumblePakOn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void controllersReadPendingData(void) {
|
||||
OSMesg msg;
|
||||
int shouldCheckStatus;
|
||||
|
||||
if (osRecvMesg(&gControllerMsgQ, &msg, OS_MESG_NOBLOCK) != -1) {
|
||||
controllerHandleMessage();
|
||||
shouldCheckStatus = controllerHandleMessage();
|
||||
} else {
|
||||
shouldCheckStatus = FALSE;
|
||||
}
|
||||
|
||||
int targetRumbleStatus = rumblePakCalculateState();
|
||||
|
||||
if (gRumblePakState == RumblepakStateInitialized) {
|
||||
int targetRumbleStatus = controllerGetTargetRumbleStatus();
|
||||
|
||||
if (gRumbleDelay > 0) {
|
||||
--gRumbleDelay;
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetRumbleStatus != gRumblePakOn) {
|
||||
shouldCheckStatus = FALSE;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
s32 rumbleError = targetRumbleStatus ? osMotorStart(&gRumbleBackFs) : osMotorStop(&gRumbleBackFs);
|
||||
|
||||
if (rumbleError == PFS_ERR_CONTRFAIL) {
|
||||
gRumblePakState = RumplepakStateUninitialized;
|
||||
continue;
|
||||
} else if (rumbleError != 0) {
|
||||
gRumblePakState = RumblepakStateDisconnected;
|
||||
gRumblePakOn = 0;
|
||||
break;
|
||||
} else {
|
||||
gRumblePakOn = targetRumbleStatus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldCheckStatus) {
|
||||
controllerQueryStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void controllersSavePreviousState(void) {
|
||||
for (unsigned i = 0; i < MAX_PLAYERS; ++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 "../menu/game_menu.h"
|
||||
#include "../effects/effect_definitions.h"
|
||||
#include "../controls/rumble_pak.h"
|
||||
|
||||
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) {
|
||||
if (playerIsDead(&scene->player)) {
|
||||
|
@ -352,6 +361,7 @@ void sceneCheckPortals(struct Scene* scene) {
|
|||
scene->player.flags |= PlayerJustShotPortalGun;
|
||||
hudPortalFired(&scene->hud, 0);
|
||||
soundPlayerPlay(soundsPortalgunShoot[0], 1.0f, 1.0f, NULL, NULL);
|
||||
rumblePakClipPlay(&gFireGunRumbleWave);
|
||||
}
|
||||
|
||||
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;
|
||||
hudPortalFired(&scene->hud, 1);
|
||||
soundPlayerPlay(soundsPortalgunShoot[1], 1.0f, 1.0f, NULL, NULL);
|
||||
rumblePakClipPlay(&gFireGunRumbleWave);
|
||||
}
|
||||
|
||||
if ((fireOrange || fireBlue) && playerIsGrabbing(&scene->player)){
|
||||
|
|
Loading…
Reference in a new issue