forked from jewalky/srvmgr
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcircle.cpp
More file actions
218 lines (177 loc) · 5.74 KB
/
circle.cpp
File metadata and controls
218 lines (177 loc) · 5.74 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include "config_new.h"
#include "a2types.h"
const char* UnitName(A2Unit* unit) {
return unit ? unit->name : "?";
}
const char* PlayerName(A2Unit* unit) {
return unit && unit->player ? unit->player->name : "??";
}
namespace circle {
int Circle(const A2Unit* unit) {
const char* name = unit->player->name;
if (name == nullptr) {
return 0;
}
char maybe_circle = name[0];
if (name[0] == '_' || name[0] == '@') {
maybe_circle = name[1];
}
if ('1' <= maybe_circle && maybe_circle <= '9') {
return static_cast<int>(maybe_circle - '0');
}
return 0;
}
double Multiplier(int circle, ServerIDType server_id) {
switch (server_id) {
case EASY: return 0.05 * circle;
case KIDS: return 0.10 * circle;
case NIVAL: return 0.15 * circle;
case MEDIUM: return 0.20 * circle;
case HARD: return 0.25 * circle;
case NIGHTMARE: return 0.30 * circle;
case QUEST_T1: return 0.25 * circle;
case QUEST_T2: return 0.20 * circle;
case QUEST_T3: return 0.15 * circle;
case QUEST_T4: return 0.10 * circle;
default: return 0.0;
}
}
int Bonus(int circle, ServerIDType server_id) {
switch (server_id) {
case EASY: return (circle + 1) / 2;
case KIDS: return circle;
case NIVAL: return circle;
case MEDIUM: return circle;
case HARD: return 2 * circle;
case NIGHTMARE: return 3 * circle;
case QUEST_T1: return 4 * circle;
case QUEST_T2: return 5 * circle;
case QUEST_T3: return 6 * circle;
case QUEST_T4: return 7 * circle;
default: return 0;
}
}
// Increase damage to units that are going through circles.
int IncreaseDamage(A2Unit* attacker, A2Unit* target, int damage) {
// Not a player's unit --- no changes.
if (!target || !target->player || target->player->is_ai != 0) {
return damage;
}
// On-map effects are not modified.
if (!attacker || !attacker->player) {
return damage;
}
// PvP is untouched.
if (attacker->player->is_ai == 0) {
return damage;
}
int circle_number = Circle(target);
if (circle_number == 0) {
return damage;
}
double multiplier = 1 + Multiplier(circle_number, Config::ServerID);
int bonus = Bonus(circle_number, Config::ServerID);
int new_damage = static_cast<int>(damage * multiplier + bonus);
return new_damage;
}
double ExperienceMultiplier(const A2Human* caster) {
return 1.0 + 0.5 * Circle(&caster->unit);
}
}
int __cdecl ChangeDamageRegular(A2Unit* attacker, A2Unit* target, int damage) {
return circle::IncreaseDamage(attacker, target, damage);
}
int __cdecl ChangeDamageSpecial(A2Unit* attacker, A2Unit* target, int damage) {
Printf("[circle/special] 0x%x -> 0x%x (%s/%s -> %s/%s) for %d", attacker, target, UnitName(attacker), PlayerName(attacker), UnitName(target), PlayerName(target), damage);
// No idea what the original logic is for. Not modfying the damage till we see some usage.
return damage;
}
int __cdecl ChangeDamageMagic(A2Unit* attacker, A2Unit* target, int damage) {
return circle::IncreaseDamage(attacker, target, damage);
}
// Address: 00536d81
void __declspec(naked) circle_damage_regular() {
__asm {
push DWORD PTR [ebp-0x1c] // Current damage.
push DWORD PTR [ebp-0x3c] // Attacker.
push DWORD PTR [ebp+0xc] // Target.
call ChangeDamageRegular
// Save new damage.
mov DWORD PTR [ebp-0x1c], eax
// Original logic.
mov ecx, DWORD PTR [ebp+0xc]
mov edx, 0
mov dl, BYTE PTR [ecx+0x4c]
and edx, 0x10
// Restore original instruction.
mov ebx, 0x00536d87
jmp ebx
}
}
// Address: 00536e1e
void __declspec(naked) circle_damage_special() {
__asm {
// Original logic.
mov cl, BYTE PTR [edx+0x11]
add eax, ecx
push eax // Current damage.
push DWORD PTR [ebp-0x3c] // Attacker.
push DWORD PTR [ebp+0xc] // Target.
call ChangeDamageSpecial
// Save new damage.
mov DWORD PTR [ebp-0x1c], eax
// Restore original instruction.
mov ebx, 0x00536e26
jmp ebx
}
}
// Address: 00536ed8
void __declspec(naked) circle_damage_magic() {
__asm {
// Original logic.
mov dl, BYTE PTR [ecx+0x13]
add eax, edx
push eax // Current damage.
push DWORD PTR [ebp-0x3c] // Attacker.
push DWORD PTR [ebp+0xc] // Target.
call ChangeDamageMagic
// Save new damage.
mov DWORD PTR [ebp-0x1c], eax
// Restore original instruction.
mov ebx, 0x00536ee0
jmp ebx
}
}
void __fastcall CircleExperience(int32_t sphere, A2Human* human) {
// Sphere is set for magic attacks. Physical attacks calculate it from unit fields.
if (IsWarrior(&human->unit)) {
sphere = human->unit.hit_values.physical_damage_type;
}
if (sphere == human->main_sphere || sphere == 5 || sphere == 0 || circle::Circle(&human->unit) == 0) {
// Don't change.
return;
}
double experience;
__asm {
fstp experience // Pop ST(0)
}
auto multiplier = circle::ExperienceMultiplier(human);
experience *= multiplier;
__asm {
fld experience // Load 'experience' back into ST(0)
}
}
// Address: 005307a3
void __declspec(naked) circle_experience() {
__asm {
mov ecx, DWORD PTR [ebp+0x10] // Magic sphere.
push edx
call CircleExperience
pop edx
// Original logic.
movsx eax, WORD PTR [edx+0x88] // Mind.
// Restore original instruction.
mov ebx, 0x005307aa
jmp ebx
}
}