forked from sashavol/Frozlunky
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoneplayer_only.cpp
134 lines (109 loc) · 3.32 KB
/
oneplayer_only.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "oneplayer_only.h"
#ifdef DEBUG_MODE
#define DISCOVERY_FUNC(FUNC) if(!FUNC()) {std::cout << "OnePlayerOnlyPatch::" << #FUNC << " failed, hooks invalidated." << std::endl; is_valid = false; return;}
#else
#define DISCOVERY_FUNC(FUNC) if(!FUNC()) {is_valid = false; return;}
#endif
OnePlayerOnlyPatch::~OnePlayerOnlyPatch() {
if(orig_char_select != nullptr) {
delete[] orig_char_select;
}
}
OnePlayerOnlyPatch::OnePlayerOnlyPatch(std::shared_ptr<Spelunky> spel, std::shared_ptr<DerandomizePatch> dp) :
Patch(spel),
is_valid(true),
orig_char_select(nullptr)
{
g_CurrentGamePtr = dp->game_ptr();
if(g_CurrentGamePtr == 0x0) {
is_valid = false;
return;
}
DISCOVERY_FUNC(discover_controller_count);
DISCOVERY_FUNC(discover_char_select_addr);
}
BYTE char_select_find[] = {
0x7A, 0xFF,
0x6A, 0x01,
0xFF,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF,
0xBB, 0x02, 0x00, 0x00, 0x00,
0xFF,
0xFF,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF,
0x6A, 0x03,
0xFF,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF,
0x6A, 0x04,
0xFF,
0xE8,
};
BYTE char_select_patch[] = {
0x90, 0x90, 0x90, 0x90, 0x90,
0x90,
0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90,
0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90,
0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
};
std::string char_select_mask = "x.xx.x....xxxxx..x....xx.x....xx.x";
bool OnePlayerOnlyPatch::discover_char_select_addr()
{
char_select_addr = spel->get_stored_hook("csoffs");
if(char_select_addr == 0x0) {
Address base = spel->find_mem(char_select_find, char_select_mask);
if(base == 0x0) {
return false;
}
char_select_addr = base+10;
#ifdef DEBUG_MODE
std::cout << "Discovered char_select_addr at " << std::setbase(16) << char_select_addr << std::endl;
#endif
spel->store_hook("csoffs", char_select_addr);
}
orig_char_select = new BYTE[sizeof(char_select_patch)];
spel->read_mem(char_select_addr, orig_char_select, sizeof(char_select_patch));
return true;
}
BYTE controller_count_find[] = {0x83, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x85, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x8B};
std::string controller_count_mask = "x.....xxx.....xxxxx";
bool OnePlayerOnlyPatch::discover_controller_count()
{
controller_count_offset = spel->get_stored_hook("ctcoffs");
if(controller_count_offset == 0x0) {
Address base = spel->find_mem(controller_count_find, controller_count_mask);
if(base == 0x0) {
return false;
}
base += 0x2;
spel->read_mem(base, &controller_count_offset, sizeof(Address));
#ifdef DEBUG_MODE
std::cout << "Discovered controller_count_offset at " << std::setbase(16) << controller_count_offset << std::endl;
#endif
spel->store_hook("ctcoffs", controller_count_offset);
}
return true;
}
bool OnePlayerOnlyPatch::_perform() {
if(char_select_addr != 0x0) {
spel->write_mem(char_select_addr, char_select_patch, sizeof(char_select_patch));
}
return true;
}
bool OnePlayerOnlyPatch::_undo() {
if(char_select_addr != 0x0) {
spel->write_mem(char_select_addr, orig_char_select, sizeof(char_select_patch));
}
return true;
}
int OnePlayerOnlyPatch::controller_count() {
Address game;
spel->read_mem(g_CurrentGamePtr, &game, sizeof(Address));
int count = 0;
spel->read_mem(game+controller_count_offset, &count, sizeof(int));
return count;
}