forked from jewalky/srvmgr
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathpartial_drop.cpp
More file actions
220 lines (187 loc) · 5.88 KB
/
partial_drop.cpp
File metadata and controls
220 lines (187 loc) · 5.88 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
219
220
#include "a2types.h"
#include "config_new.h"
#define _USE_MATH_DEFINES
#include "math.h"
#include "this_call.h"
#include "solo.h"
void* (__cdecl *a2_operator_new)(int) = (void* (*)(int))0x005DDF54;
auto a2_delete = (void (__cdecl *)(void*))0x005ddf90;
auto a2_bag_destructor = (void (__fastcall *)(A2InventoryList*))0x00551c7a;
A2InventoryList* __stdcall create_new_item_list()
{
#define FUNC_ITEM_LIST_CONSTRUCTOR 0x00551C0A
A2InventoryList* list = (A2InventoryList*)a2_operator_new(0x24);
return (A2InventoryList*)this_call(FUNC_ITEM_LIST_CONSTRUCTOR, list);
}
float rnd()
{
return (float)rand() / (RAND_MAX + 1);
}
float rnd_gaussian(float mu, float sigma)
{
float u1, u2;
float two_pi = static_cast<float>(2.0 * M_PI);
u1 = rnd();
u2 = rnd();
float z0 = static_cast<float>(sqrt(-2.0 * log(u1)) * cos(two_pi * u2));
return z0 * sigma + mu;
}
void a2insert(A2InventoryList * list, int pos, A2InventoryItem* item)
{
this_call(0x00551FC3, (void*)list, (void*)pos, (void*)item);
}
void a2insert(A2InventoryList * list, A2InventoryItem* item)
{
a2insert(list, list->maxInd, item);
}
A2InventoryItem* a2remove(A2InventoryList * list, int pos, int n)
{
return (A2InventoryItem*)this_call(0x00552E42, (void*)list, (void*)pos, (void*)n);
}
struct IndNum
{
__int16 ind;
__int16 num;
};
float limit(float n, float lo, float hi)
{
if (n < lo)
return lo;
if (n > hi)
return hi;
return n;
}
int round_num(float a)
{
return (int)(a+0.5f);
}
int getDropNum(int num, float probability)
{
int dropN = 0;
if (probability == 0)
dropN = 0;
else if (probability == 1)
dropN = num;
else
{
if (num == 1)
{
if (rnd() < probability)
dropN = 1;
}
else
{
float odds = limit(rnd_gaussian(probability, 0.1f), 0, 1);
dropN = round_num(odds * num);
}
}
return dropN;
}
void __stdcall drop_rnd_items(A2InventoryList* item_list_src, A2InventoryList* item_list_dst, float probability) {
A2Node<A2InventoryItem>* src_current = item_list_src->list.last_node;
int ind = item_list_src->list.size - 1;
std::vector<IndNum> to_remove;
while (src_current != NULL)
{
if (src_current->value->id == 3667) {
ind--;
src_current = src_current->prev;
continue;
}
int dropN = getDropNum(src_current->value->amount, probability);
if (dropN > 0)
{
IndNum item;
item.ind = ind;
item.num = dropN;
to_remove.push_back(item);
}
ind--;
src_current = src_current->prev;
}
for (std::vector<IndNum>::iterator it = to_remove.begin() ; it != to_remove.end(); ++it) {
a2insert(item_list_dst, 0, a2remove(item_list_src, it->ind, it->num));
}
}
void __stdcall drop_rnd_weared_items(A2Unit* unit, A2InventoryList* item_list_dst, float probability) {
if (unit->clazz != A2_CLASS_HUMAN) {
return; // unit does not support worn items
}
const A2Human* human = reinterpret_cast<A2Human*>(unit);
for (int i = -2; i < 13; ++i ) {
A2InventoryItem* item = (i == -2 ? unit->weapon : i == -1 ? unit->shield : human->dress[i]);
if (i == -2 && IsPurePlayer(unit)) {
continue; // Pure players keep their weapon on death
}
if (item && getDropNum(1, probability) > 0) {
a2insert(item_list_dst, unit->clazz->UnitUnequip(unit, item));
}
}
}
void CopyInventoryToMap(A2Unit *unit, A2InventoryList *inventory, int money, int main_unit) {
if (inventory->list.size || money) {
this_call(0x0052D8D3, (void *)unit, (void *)inventory, (void *)money, (void *)main_unit);
}
}
bool isPlayerUnit(A2Unit* unit)
{
return unit->player->is_ai == 0;
}
void DeleteInventory(A2InventoryList* bag) {
a2_bag_destructor(bag);
a2_delete(bag);
}
void __fastcall drop_partially(A2Unit* unit, int unused_edx, A2InventoryList* unused, int money, int main_unit) {
Printf("drop_partially: unit=0x%x, money=%d, main_unit=%d", unit, money, main_unit);
if (!unit) {
return;
}
if (isPlayerUnit(unit)) {
A2InventoryList* bag = create_new_item_list();
drop_rnd_items(unit->inventory, bag, Config::InventoryDropProbability);
drop_rnd_weared_items(unit, bag, Config::WearDropProbability);
if (bag->list.size) {
PoisonStapleCell(unit->position);
}
if (IsGigaPlayer(unit) || IsPurePlayer(unit)) {
DeleteInventory(bag);
} else {
CopyInventoryToMap(unit, bag, money, main_unit);
}
} else if (unit->inventory) {
StapleCellOnMobKill(unit);
// If this is a monster, we drop all items like it's done in original a2
CopyInventoryToMap(unit, unit->inventory, money, main_unit);
unit->inventory = create_new_item_list();
}
}
void __declspec(naked) imp_drop_partially()
{ // 0052E264
__asm
{
// All parameters are taken from the stack and ECX.
call drop_partially
mov edx, 0x0052e2c8
jmp edx
}
}
void __stdcall update_unit_ui_wrapper(A2Unit *unit, int a){
__asm
{
mov edx, a
push edx
mov edx, unit
push edx
mov ecx, 0x006C3A08
mov edx, 0x51C601
call edx
}
}
// Address: 0052da11
void __declspec(naked) partial_drop_skip_undress() {
__asm {
// Skip putting weapon, shield and all equipped items into the inventory.
mov eax, 0x0052daab
jmp eax
}
}