Skip to content

Commit f514ab5

Browse files
committed
Add support for two gamepads
1 parent c96e0c9 commit f514ab5

File tree

16 files changed

+245
-251
lines changed

16 files changed

+245
-251
lines changed

smw.ini

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v
6666
# This one is suitable for AZERTY keyboards.
6767
#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v
6868

69+
# For player 2
70+
#ControlsP2 = Shift+Up, Shift+Down, Shift+Left, Shift+Right, Shift+Right Shift, Shift+Return, Shift+x, Shift+z, Shift+s, Shift+a, Shift+c, Shift+v
71+
6972
CheatLife = w
7073
CheatJump = Ctrl+q
7174
ClearKeyLog = k
@@ -90,7 +93,14 @@ LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace
9093
ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace
9194

9295
[GamepadMap]
96+
# Whether the gamepads will be enabled. The game will not use them unless they're on.
97+
EnableGamepad1 = true
98+
EnableGamepad2 = true
99+
93100
# Any keys used in KeyMap can be used also in this section.
101+
94102
# The shoulder button is called L1/Lb and L2, and the thumbstick button is called L3
95-
Controls = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb
103+
Controls = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb
96104

105+
# For player 2.
106+
ControlsP2 = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb

src/common_cpu_infra.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ static uint8 kPatchedCarrysOrg[1024];
3232
static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev);
3333
static void MakeSnapshot(Snapshot *s);
3434
static void RestoreSnapshot(Snapshot *s);
35-
static void RtlRunFrameCompare(uint16 input, int run_what);
3635

3736
uint8_t *SnesRomPtr(uint32 v) {
3837
return (uint8 *)RomPtr(v);
@@ -252,8 +251,6 @@ Snes *SnesInit(const uint8 *data, int data_size) {
252251
g_dma = g_snes->dma;
253252
g_use_my_apu_code = (g_runmode != RM_THEIRS);
254253

255-
RtlSetupEmuCallbacks(NULL, &RtlRunFrameCompare, NULL);
256-
257254
if (data_size != 0 && g_runmode != RM_MINE) {
258255
bool loaded = snes_loadRom(g_snes, data, data_size);
259256
if (!loaded) {
@@ -362,9 +359,7 @@ void RunOneFrameOfGame_Both(void) {
362359
g_got_mismatch_count--;
363360
}
364361

365-
static void RtlRunFrameCompare(uint16 input, int run_what) {
366-
g_snes->input1->currentState = input;
367-
362+
void RtlRunFrameCompare() {
368363
g_use_my_apu_code = (g_runmode != RM_THEIRS);
369364

370365
if (g_runmode == RM_THEIRS) {

src/common_cpu_infra.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ typedef void CpuInfraInitializeFunc(void);
2121
typedef void RunOneFrameOfGameFunc(void);
2222
typedef void FixSnapshotForCompareFunc(Snapshot *b, Snapshot *a);
2323

24+
void RtlRunFrameCompare(void);
25+
2426
typedef struct RtlGameInfo {
2527
const char *title;
2628
uint8 game_id;

src/common_rtl.c

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,6 @@ Ppu *g_ppu, *g_my_ppu;
2626
Dma *g_dma;
2727
bool g_custom_music;
2828

29-
static uint8 *g_rtl_memory_ptr;
30-
static RunFrameFunc *g_rtl_runframe;
31-
static SyncAllFunc *g_rtl_syncall;
32-
33-
void RtlSetupEmuCallbacks(uint8 *emu_ram, RunFrameFunc *func, SyncAllFunc *sync_all) {
34-
g_rtl_memory_ptr = emu_ram;
35-
g_rtl_runframe = func;
36-
g_rtl_syncall = sync_all;
37-
}
38-
39-
static void RtlSynchronizeWholeState(void) {
40-
if (g_rtl_syncall)
41-
g_rtl_syncall();
42-
}
43-
44-
// |ptr| must be a pointer into g_ram, will synchronize the RAM memory with the
45-
// emulator.
46-
static void RtlSyncMemoryRegion(void *ptr, size_t n) {
47-
uint8 *data = (uint8 *)ptr;
48-
assert(data >= g_ram && data < g_ram + 0x20000);
49-
if (g_rtl_memory_ptr)
50-
memcpy(g_rtl_memory_ptr + (data - g_ram), data, n);
51-
}
52-
5329
void ByteArray_AppendVl(ByteArray *arr, uint32 v) {
5430
for (; v >= 255; v -= 255)
5531
ByteArray_AppendByte(arr, 255);
@@ -81,15 +57,14 @@ void loadFunc(SaveLoadInfo *sli, void *data, size_t data_size) {
8157
static void LoadSnesState(SaveLoadInfo *sli) {
8258
// Do the actual loading
8359
snes_saveload(g_snes, sli);
84-
RtlSynchronizeWholeState();
8560
}
8661

8762
static void SaveSnesState(SaveLoadInfo *sli) {
8863
snes_saveload(g_snes, sli);
8964
}
9065

9166
typedef struct StateRecorder {
92-
uint16 last_inputs;
67+
uint32 last_inputs;
9368
uint32 frames_since_last;
9469
uint32 total_frames;
9570

@@ -100,6 +75,7 @@ typedef struct StateRecorder {
10075
uint32 snapshot_flags;
10176
uint8 replay_cmd;
10277
bool replay_mode;
78+
uint8 cur_player;
10379

10480
ByteArray log;
10581
ByteArray base_snapshot;
@@ -122,25 +98,31 @@ void StateRecorder_RecordCmd(StateRecorder *sr, uint8 cmd) {
12298
ByteArray_AppendVl(&sr->log, frames - x);
12399
}
124100

125-
void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
126-
uint16 diff = inputs ^ sr->last_inputs;
127-
if (diff != 0) {
128-
sr->last_inputs = inputs;
129-
// printf("0x%.4x %d: ", diff, sr->frames_since_last);
130-
// size_t lb = sr->log.size;
131-
for (int i = 0; i < 12; i++) {
132-
if ((diff >> i) & 1)
133-
StateRecorder_RecordCmd(sr, i << 4);
101+
static void StateRecorder_RecordKeyDiff(StateRecorder *sr, uint32 diff) {
102+
for (int i = 0; diff; i++, diff >>= 1) {
103+
if (diff & 1) {
104+
int player = (i >= 12);
105+
i -= player * 12;
106+
if (player != sr->cur_player) {
107+
sr->cur_player = player;
108+
ByteArray_AppendByte(&sr->log, 0xfc + player);
109+
}
110+
StateRecorder_RecordCmd(sr, i << 4);
134111
}
135-
// while (lb < sr->log.size)
136-
// printf("%.2x ", sr->log.data[lb++]);
137-
// printf("\n");
138112
}
113+
}
114+
115+
void StateRecorder_Record(StateRecorder *sr, uint32 inputs) {
116+
uint32 diff = (inputs ^ sr->last_inputs) & 0xffffff;
117+
sr->last_inputs = inputs;
118+
if (diff)
119+
StateRecorder_RecordKeyDiff(sr, diff);
139120
sr->frames_since_last++;
140121
sr->total_frames++;
141122
}
142123

143-
void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
124+
void StateRecorder_RecordPatchByte(StateRecorder *sr, const uint8 *value, int num) {
125+
uint32 addr = value - g_ram;
144126
assert(addr < 0x20000);
145127

146128
// printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
@@ -174,8 +156,6 @@ void RtlReset(int mode) {
174156
RtlRestoreMusicAfterLoad_Locked(true);
175157
RtlApuUnlock();
176158

177-
RtlSynchronizeWholeState();
178-
179159
if ((mode & 2) == 0)
180160
StateRecorder_Init(&state_recorder);
181161
}
@@ -216,6 +196,7 @@ void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
216196
sr->snapshot_flags = hdr[9];
217197
sr->replay_next_cmd_at = 0;
218198
sr->replay_mode = replay_mode;
199+
sr->cur_player = 0;
219200
if (replay_mode) {
220201
sr->frames_since_last = 0;
221202
sr->last_inputs = 0;
@@ -269,6 +250,12 @@ void StateRecorder_Save(StateRecorder *sr, FILE *f, bool saving_with_bug) {
269250
assert(sr->base_snapshot.size == 0 ||
270251
sr->base_snapshot.size == savest.array.size || sr->base_snapshot.size == g_sram_size);
271252

253+
// Before saving, reset the cur player
254+
if (sr->cur_player) {
255+
sr->cur_player = 0;
256+
ByteArray_AppendVl(&sr->log, 0xfc);
257+
}
258+
272259
hdr[0] = 2;
273260
hdr[1] = sr->total_frames;
274261
hdr[2] = (uint32)sr->log.size;
@@ -305,12 +292,9 @@ void StateRecorder_ClearKeyLog(StateRecorder *sr) {
305292
memset(&sr->log, 0, sizeof(sr->log));
306293
// If there are currently any active inputs, record them initially at timestamp 0.
307294
sr->frames_since_last = 0;
308-
if (sr->last_inputs) {
309-
for (int i = 0; i < 12; i++) {
310-
if ((sr->last_inputs >> i) & 1)
311-
StateRecorder_RecordCmd(sr, i << 4);
312-
}
313-
}
295+
sr->cur_player = 0;
296+
StateRecorder_RecordKeyDiff(sr, sr->last_inputs);
297+
314298
if (sr->replay_mode) {
315299
// When clearing the key log while in replay mode, we want to keep
316300
// replaying but discarding all key history up until this point.
@@ -340,7 +324,7 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
340324
// Apply next command
341325
sr->frames_since_last = 0;
342326
if (sr->replay_cmd < 0xc0) {
343-
sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
327+
sr->last_inputs ^= 1 << ((sr->replay_cmd >> 4) + sr->cur_player * 12);
344328
} else if (sr->replay_cmd < 0xd0) {
345329
int nb = 1 + ((sr->replay_cmd >> 2) & 3);
346330
uint8 t;
@@ -352,7 +336,6 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
352336
addr |= sr->log.data[replay_pos++];
353337
do {
354338
g_ram[addr & 0x1ffff] = sr->log.data[replay_pos++];
355-
RtlSyncMemoryRegion(&g_ram[addr & 0x1ffff], 1);
356339
} while (addr++, --nb);
357340
} else {
358341
assert(0);
@@ -365,7 +348,20 @@ uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
365348
break;
366349
}
367350
// Read the next one
368-
uint8 cmd = sr->log.data[replay_pos++], t;
351+
uint8 cmd, t;
352+
353+
for (;;) {
354+
cmd = sr->log.data[replay_pos++];
355+
if (cmd < 0xfc)
356+
break;
357+
switch (cmd) {
358+
case 0xfc:
359+
case 0xfd: sr->cur_player = cmd - 0xfc; break;
360+
default:
361+
assert(0);
362+
}
363+
}
364+
369365
int mask = (cmd < 0xc0) ? 0xf : 0x1;
370366
int frames = cmd & mask;
371367
if (frames == mask) do {
@@ -400,7 +396,8 @@ void RtlStopReplay(void) {
400396
StateRecorder_StopReplay(&state_recorder);
401397
}
402398

403-
bool RtlRunFrame(int inputs) {
399+
bool RtlRunFrame(uint32 inputs) {
400+
404401
if (g_did_finish_level_hook) {
405402
if (game_id == kGameID_SMW && !state_recorder.replay_mode && g_config.save_playthrough) {
406403
SmwSavePlaythroughSnapshot();
@@ -414,6 +411,9 @@ bool RtlRunFrame(int inputs) {
414411
// Avoid up/down and left/right from being pressed at the same time
415412
if ((inputs & 0x30) == 0x30) inputs ^= 0x30;
416413
if ((inputs & 0xc0) == 0xc0) inputs ^= 0xc0;
414+
// Player2
415+
if ((inputs & 0x30000) == 0x30000) inputs ^= 0x30000;
416+
if ((inputs & 0xc0000) == 0xc0000) inputs ^= 0xc0000;
417417

418418
bool is_replay = state_recorder.replay_mode;
419419

@@ -433,12 +433,21 @@ bool RtlRunFrame(int inputs) {
433433
uint8 apui02 = RtlApuReadReg(2);
434434
if (apui02 != g_ram[kSmwRam_APUI02]) {
435435
g_ram[kSmwRam_APUI02] = apui02;
436-
StateRecorder_RecordPatchByte(&state_recorder, kSmwRam_APUI02, &apui02, 1);
436+
StateRecorder_RecordPatchByte(&state_recorder, &g_ram[kSmwRam_APUI02], 1);
437+
}
438+
// Whether controllers are plugged in.
439+
uint32 new_my_flags = inputs >> 30;
440+
if (new_my_flags != g_ram[kSmwRam_my_flags]) {
441+
assert(new_my_flags <= 255);
442+
g_ram[kSmwRam_my_flags] = new_my_flags;
443+
StateRecorder_RecordPatchByte(&state_recorder, &g_ram[kSmwRam_my_flags], 1);
437444
}
438445
}
439446
}
447+
g_snes->input1_currentState = inputs & 0xfff;
448+
g_snes->input2_currentState = (inputs >> 12) & 0xfff;
440449

441-
g_rtl_runframe(inputs, 0);
450+
RtlRunFrameCompare();
442451

443452
snes_frame_counter++;
444453

@@ -462,7 +471,6 @@ static void RtlLoadFromFile(FILE *f, bool replay) {
462471
ppu_copy(g_my_ppu, g_snes->ppu);
463472

464473
RtlApuUnlock();
465-
RtlSynchronizeWholeState();
466474
}
467475

468476
static const char *const kBugSaves[] = {
@@ -789,7 +797,6 @@ void RtlReadSram(void) {
789797
if (fread(g_sram, 1, g_sram_size, f) != g_sram_size)
790798
fprintf(stderr, "Error reading %s\n", filename);
791799
fclose(f);
792-
RtlSynchronizeWholeState();
793800
ByteArray_Resize(&state_recorder.base_snapshot, g_sram_size);
794801
memcpy(state_recorder.base_snapshot.data, g_sram, g_sram_size);
795802
}

src/common_rtl.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum {
1515
kCurrentBugFixCounter = 1,
1616

1717
kSmwRam_APUI02 = 0x18c5,
18+
kSmwRam_my_flags = 0x19C7C,
1819
};
1920

2021
typedef struct SimpleHdma {
@@ -103,12 +104,7 @@ uint8 ReadReg(uint16 reg);
103104
uint8_t *IndirPtr(LongPtr ptr, uint16 offs);
104105
void IndirWriteByte(LongPtr ptr, uint16 offs, uint8 value);
105106

106-
107-
typedef void RunFrameFunc(uint16 input, int run_what);
108-
typedef void SyncAllFunc();
109-
110107
void RtlReset(int mode);
111-
void RtlSetupEmuCallbacks(uint8 *emu_ram, RunFrameFunc *func, SyncAllFunc *sync_all);
112108
void RtlClearKeyLog();
113109
void RtlStopReplay();
114110

@@ -127,7 +123,7 @@ void RtlSetUploadingApu(bool uploading);
127123
void RtlApuUpload(const uint8 *p);
128124
void RtlRenderAudio(int16 *audio_buffer, int samples, int channels);
129125
void RtlPushApuState();
130-
bool RtlRunFrame(int inputs);
126+
bool RtlRunFrame(uint32 inputs);
131127
void RtlReadSram();
132128
void RtlWriteSram();
133129
void RtlSaveSnapshot(const char *filename, bool saving_with_bug);

0 commit comments

Comments
 (0)