Files
vbagx/source/ngc/inputmetroid.cpp
dborth 2d9b7ef1f9 [1.0.8 - April 4, 2009]
* "Match Wii Game" controls option! Games that have a Wii equivalent can be
  played using the controls for that Wii game. For example all Zelda games
  can be played with Twilight Princess controls. See the Instructions section
  below for important details.
* Rotation/Tilt sensor games all work
* Solar sensors (Boktai 1/2/3)
* Rumble (except for games that rely on Gameboy Player)
* Keyboard
* PAL support, finally!
* New scaling options, choose how much stretching you want
* Colourised games now partially work but still have distortion
* "Corvette" no longer has a screwed up palette (but still crashes)
* Triggers net reconnection on SMB failure
* Source code refactored, and project file added
* Instructions section added to this readme file
2009-04-10 03:16:28 +00:00

656 lines
15 KiB
C++

/****************************************************************************
* Visual Boy Advance GX
*
* Carl Kenner Febuary 2009
*
* gameinput.cpp
*
* Wii/Gamecube controls for individual games
***************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ogcsys.h>
#include <unistd.h>
#include <wiiuse/wpad.h>
#include "vba.h"
#include "button_mapping.h"
#include "audio.h"
#include "video.h"
#include "input.h"
#include "gameinput.h"
#include "vbasupport.h"
#include "wiiusbsupport.h"
#include "gba/GBA.h"
#include "gba/bios.h"
#include "gba/GBAinline.h"
u32 MetroidZeroInput(unsigned short pad) {
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeClassic(pad) | DecodeKeyboard(pad);
u8 BallState = CPUReadByte(0x30015df); // 0 = stand, 1 = crouch, 2 = ball
u16 Health = CPUReadByte(0x3001536); // 0 = stand, 1 = crouch, 2 = ball
static u16 OldHealth = 0;
// Rumble when they lose health!
if (Health < OldHealth)
systemGameRumble(20);
OldHealth = Health;
static int Morph = 0;
static int AimCount = 0;
static int MissileCount = 0;
if (BallState == 2) // Can't exit morph ball without pressing C!
J &= ~VBA_UP;
if (BallState == 1) // Can't enter morph ball without pressing C!
J &= ~VBA_DOWN;
#ifdef HW_RVL
WPADData * wp = WPAD_Data(pad);
if (wp->btns_h & WPAD_BUTTON_UP)
J |= VBA_SPEED;
if (wp->btns_h & WPAD_BUTTON_LEFT)
J |= VBA_BUTTON_L;
if (wp->btns_h & WPAD_BUTTON_RIGHT)
J |= VBA_BUTTON_R;
// Visor doesn't exist, use as start button
if (wp->btns_h & WPAD_BUTTON_MINUS)
J |= VBA_BUTTON_START;
// Hyper (toggle super missiles)
if (wp->btns_h & WPAD_BUTTON_PLUS)
J |= VBA_BUTTON_SELECT;
// Map
if (wp->btns_h & WPAD_BUTTON_1)
J |= VBA_BUTTON_START;
// Hint
if (wp->btns_h & WPAD_BUTTON_2)
J |= VBA_BUTTON_R;
// Z-Target
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_h & WPAD_NUNCHUK_BUTTON_Z))
;
// Jump
if (wp->btns_h & WPAD_BUTTON_B && BallState!=2)
J |= VBA_BUTTON_A;
else if (BallState==2 && fabs(wp->gforce.y)> 1.5)
J |= VBA_BUTTON_A;
// Fire
if (wp->btns_h & WPAD_BUTTON_A)
J |= VBA_BUTTON_B;
// Aim
/*if (CursorValid && CursorY < 96 && BallState!=2)
J |= VBA_UP;
else if (CursorValid && CursorY < 192 && BallState!=2)
J |= VBA_BUTTON_L;
else if (CursorValid && CursorY < 288 && BallState!=2)
J |= 0;
else if (CursorValid && CursorY < 384 && BallState!=2)
J |= VBA_BUTTON_L & VBA_DOWN;
else if (CursorValid && BallState==0)
J |= VBA_DOWN;*/
if (wp->orient.pitch < -45 && BallState !=2) {
J |= VBA_UP;
AimCount = 0;
} else if (wp->orient.pitch < -22 && BallState !=2) {
if (AimCount>=0) AimCount = -1;
} else if (wp->orient.pitch> 45 && BallState ==0) {
if (AimCount<10) AimCount=10;
} else if (wp->orient.pitch> 22 && BallState !=2) {
if (AimCount<=0 || AimCount>=10) AimCount = 1;
} else {
AimCount=0;
}
// Morph Ball
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_d & WPAD_NUNCHUK_BUTTON_C)) {
if (BallState == 2) { // ball
Morph = -1;
} else if (BallState == 1) {
Morph = 2;
} else {
Morph = 1;
}
}
// Missile
if (wp->btns_h & WPAD_BUTTON_DOWN) {
MissileCount = 1;
}
switch (AimCount) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L;
AimCount++;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L | VBA_DOWN;
AimCount++;
break;
case 3:
J |= VBA_BUTTON_L;
break;
case -1:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= 0;
AimCount--;
break;
case -2:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L;
AimCount--;
break;
case -3:
J |= VBA_BUTTON_L;
break;
case 10:
J |= VBA_BUTTON_A;
AimCount++;
break;
case 11:
J |= VBA_DOWN;
AimCount++;
break;
case 12:
J |= VBA_DOWN;
break;
}
switch (MissileCount) {
case 1:
case 2:
J |= VBA_BUTTON_R;
MissileCount++;
break;
case 3:
case 4:
J |= VBA_BUTTON_R | VBA_BUTTON_B;
MissileCount++;
break;
case 5:
MissileCount = 0;
break;
}
switch (Morph) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 2;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph = 3;
break;
case 3:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 0;
break;
case -1:
case -2:
case -3:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -4:
case -5:
case -6:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph--;
break;
case -7:
case -8:
case -9:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -10:
Morph = 0;
break;
}
#endif
return J;
}
u32 MetroidFusionInput(unsigned short pad) {
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeClassic(pad) | DecodeKeyboard(pad);
u8 BallState = CPUReadByte(0x3001329); // 0 = stand, 2 = crouch, 5 = ball
u16 Health = CPUReadHalfWord(0x3001310);
static u16 OldHealth = 0;
// Rumble when they lose health!
if (Health < OldHealth)
systemGameRumble(20);
OldHealth = Health;
static int Morph = 0;
static int AimCount = 0;
static int MissileCount = 0;
if (BallState == 5) // Can't exit morph ball without pressing C!
J &= ~VBA_UP;
if (BallState == 2) // Can't enter morph ball without pressing C!
J &= ~VBA_DOWN;
#ifdef HW_RVL
WPADData * wp = WPAD_Data(pad);
if (wp->btns_h & WPAD_BUTTON_LEFT)
J |= VBA_BUTTON_L;
if (wp->btns_h & WPAD_BUTTON_RIGHT)
J |= VBA_BUTTON_R;
// Visor doesn't exist, just use as select button
if (wp->btns_h & WPAD_BUTTON_MINUS)
J |= VBA_BUTTON_SELECT;
// Hyper isn't available, just use start button as start
if (wp->btns_h & WPAD_BUTTON_PLUS)
J |= VBA_BUTTON_START;
// Map
if (wp->btns_h & WPAD_BUTTON_1)
J |= VBA_BUTTON_START;
// Hint
if (wp->btns_h & WPAD_BUTTON_2)
J |= VBA_BUTTON_R;
// Z-Target
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_h & WPAD_NUNCHUK_BUTTON_Z))
J |= VBA_SPEED;
// Jump
if (wp->btns_h & WPAD_BUTTON_B && BallState!=5)
J |= VBA_BUTTON_A;
else if (BallState==5 && fabs(wp->gforce.y)> 1.5)
J |= VBA_BUTTON_A;
// Fire
if (wp->btns_h & WPAD_BUTTON_A)
J |= VBA_BUTTON_B;
// Aim
if (wp->orient.pitch < -45 && BallState !=5) {
J |= VBA_UP;
AimCount = 0;
} else if (wp->orient.pitch < -22 && BallState !=5) {
if (AimCount>=0) AimCount = -1;
} else if (wp->orient.pitch> 45 && BallState !=5) {
if (AimCount<10) AimCount=10;
} else if (wp->orient.pitch> 22 && BallState !=5) {
if (AimCount<=0 || AimCount>=10) AimCount = 1;
} else {
AimCount=0;
}
// Morph Bdall
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_d & WPAD_NUNCHUK_BUTTON_C)) {
if (BallState == 5) { // ball
Morph = -1;
} else if (BallState == 2) {
Morph = 2;
} else {
Morph = 1;
}
}
// Missile
if (wp->btns_h & WPAD_BUTTON_DOWN) {
MissileCount = 1;
}
#endif
switch (AimCount) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L;
AimCount++;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L | VBA_DOWN;
AimCount++;
break;
case 3:
J |= VBA_BUTTON_L;
break;
case -1:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= 0;
AimCount--;
break;
case -2:
J &= ~(VBA_UP | VBA_DOWN | VBA_BUTTON_L);
J |= VBA_BUTTON_L;
AimCount--;
break;
case -3:
J |= VBA_BUTTON_L;
break;
case 10:
case 11:
J |= VBA_BUTTON_A;
AimCount++;
break;
case 12:
case 13:
J |= VBA_DOWN;
AimCount++;
break;
case 14:
J |= VBA_DOWN;
break;
}
switch (MissileCount) {
case 1:
case 2:
J |= VBA_BUTTON_R;
MissileCount++;
break;
case 3:
case 4:
J |= VBA_BUTTON_R | VBA_BUTTON_B;
MissileCount++;
break;
case 5:
MissileCount = 0;
break;
}
switch (Morph) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 2;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph = 3;
break;
case 3:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 0;
break;
case -1:
case -2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -3:
case -4:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph--;
break;
case -5:
case -6:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -7:
Morph = 0;
break;
}
return J;
}
u32 Metroid1Input(unsigned short pad) {
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeClassic(pad) | DecodeKeyboard(pad);
u8 BallState = CPUReadByte(0x3007500); // 3 = ball, other = stand
u8 MissileState = CPUReadByte(0x300730E); // 1 = missile, 0 = beam
u16 Health = CPUReadHalfWord(0x3007306); // Binary Coded Decimal
static u16 OldHealth = 0;
// Rumble when they lose health!
if (Health < OldHealth)
systemGameRumble(20);
OldHealth = Health;
static int Morph = 0;
if (BallState == 3) // Can't exit morph ball without pressing C!
J &= ~VBA_UP;
if (BallState != 3) // Can't enter morph ball without pressing C!
J &= ~VBA_DOWN;
#ifdef HW_RVL
WPADData * wp = WPAD_Data(pad);
// No visors
if (wp->btns_h & WPAD_BUTTON_MINUS)
J |= VBA_BUTTON_SELECT;
// Start button just pauses
if (wp->btns_h & WPAD_BUTTON_PLUS)
J |= VBA_BUTTON_START;
// Map (doesn't exist)
if (wp->btns_h & WPAD_BUTTON_1)
J |= VBA_BUTTON_START;
// Hint (doesn't exist)
if (wp->btns_h & WPAD_BUTTON_2)
J |= VBA_SPEED;
// Z-Target
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_h & WPAD_NUNCHUK_BUTTON_Z))
;
// Jump
if (wp->btns_h & WPAD_BUTTON_B && BallState!=5)
J |= VBA_BUTTON_A;
else if (BallState==5 && fabs(wp->gforce.y)> 1.5)
J |= VBA_BUTTON_A;
// Fire
if (wp->btns_h & WPAD_BUTTON_A) {
if (MissileState)
J |= VBA_BUTTON_SELECT;
else
J |= VBA_BUTTON_B;
}
// Aim
if (wp->orient.pitch < -45 && BallState !=3)
J |= VBA_UP;
// Morph Ball
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_d & WPAD_NUNCHUK_BUTTON_C)) {
if (BallState == 3) { // ball
Morph = -1;
} else {
Morph = 2;
}
}
// Missile
if (wp->btns_h & WPAD_BUTTON_DOWN) {
if (!(MissileState))
J |= VBA_BUTTON_SELECT;
else
J |= VBA_BUTTON_B;
} if (wp->btns_u & WPAD_BUTTON_DOWN) {
if (MissileState)
J |= VBA_BUTTON_SELECT;
}
#endif
switch (Morph) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 2;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph = 3;
break;
case 3:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 0;
break;
case -1:
case -2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -3:
case -4:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph--;
break;
case -5:
case -6:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -7:
Morph = 0;
break;
}
return J;
}
u32 Metroid2Input(unsigned short pad) {
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeClassic(pad) | DecodeKeyboard(pad);
u8 BallState = gbReadMemory(0xD020); // 4 = crouch, 5 = ball, other = stand
u8 MissileState = gbReadMemory(0xD04D); // 8 = missile hatch open, 0 = missile closed
u8 Health = gbReadMemory(0xD051); // Binary Coded Decimal
static u8 OldHealth = 0;
// Rumble when they lose (or gain) health! (since I'm not checking energy tanks)
if (Health != OldHealth)
systemGameRumble(20);
OldHealth = Health;
static int Morph = 0;
static int AimCount = 0;
if (BallState == 5) // Can't exit morph ball without pressing C!
J &= ~VBA_UP;
if (BallState == 4) // Can't enter morph ball without pressing C!
J &= ~VBA_DOWN;
#ifdef HW_RVL
WPADData * wp = WPAD_Data(pad);
// No visors
if (wp->btns_h & WPAD_BUTTON_MINUS)
J |= VBA_BUTTON_SELECT;
// Start button just pauses
if (wp->btns_h & WPAD_BUTTON_PLUS)
J |= VBA_BUTTON_START;
// Map (doesn't exist)
if (wp->btns_h & WPAD_BUTTON_1)
J |= VBA_BUTTON_START;
// Hint (doesn't exist)
if (wp->btns_h & WPAD_BUTTON_2)
J |= VBA_SPEED;
// Z-Target
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_h & WPAD_NUNCHUK_BUTTON_Z))
;
// Jump
if (wp->btns_h & WPAD_BUTTON_B && BallState!=5)
J |= VBA_BUTTON_A;
else if (BallState==5 && fabs(wp->gforce.y)> 1.5)
J |= VBA_BUTTON_A;
// Fire
if (wp->btns_h & WPAD_BUTTON_A) {
if (MissileState & 8)
J |= VBA_BUTTON_SELECT;
else
J |= VBA_BUTTON_B;
}
// Aim
/*if (CursorValid && CursorY < 96 && BallState!=2)
J |= VBA_UP;
else if (CursorValid && CursorY < 192 && BallState!=2)
J |= VBA_BUTTON_L;
else if (CursorValid && CursorY < 288 && BallState!=2)
J |= 0;
else if (CursorValid && CursorY < 384 && BallState!=2)
J |= VBA_BUTTON_L & VBA_DOWN;
else if (CursorValid && BallState==0)
J |= VBA_DOWN;*/
if (wp->orient.pitch < -45 && BallState !=5) {
J |= VBA_UP;
AimCount = 0;
} else if (wp->orient.pitch> 45 && BallState !=5 && BallState !=4) {
//if (AimCount<10) AimCount=10;
} else {
AimCount=0;
}
// Morph Ball
if ((wp->exp.type == WPAD_EXP_NUNCHUK) && (wp->btns_d & WPAD_NUNCHUK_BUTTON_C)) {
if (BallState == 5) { // ball
Morph = -1;
} else if (BallState == 4) {
Morph = 2;
} else {
Morph = 1;
}
}
// Missile
if (wp->btns_h & WPAD_BUTTON_DOWN) {
if (!(MissileState & 8))
J |= VBA_BUTTON_SELECT;
else
J |= VBA_BUTTON_B;
}
if (wp->btns_u & WPAD_BUTTON_DOWN) {
if (MissileState & 8)
J |= VBA_BUTTON_SELECT;
}
#endif
switch (Morph) {
case 1:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 2;
break;
case 2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph = 3;
break;
case 3:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_DOWN;
Morph = 0;
break;
case -1:
case -2:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -3:
case -4:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
Morph--;
break;
case -5:
case -6:
J &= ~(VBA_UP | VBA_DOWN | VBA_LEFT | VBA_RIGHT | VBA_BUTTON_L);
J |= VBA_UP;
Morph--;
break;
case -7:
Morph = 0;
break;
}
return J;
}