Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Puyo/PuyoAI.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PuyoAI Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPuyoAI *PuyoAI;
11
12
void PuyoAI_Update(void) {}
13
14
void PuyoAI_LateUpdate(void) {}
15
16
void PuyoAI_StaticUpdate(void) {}
17
18
void PuyoAI_Draw(void) {}
19
20
void PuyoAI_Create(void *data) {}
21
22
void PuyoAI_StageLoad(void) {}
23
24
Vector2 PuyoAI_GetBeanPos(int32 playerID)
25
{
26
Vector2 pos = { -1, -1 };
27
28
foreach_all(PuyoBean, bean)
29
{
30
if (bean->stateInput && bean->state == PuyoBean_State_Controlled && bean->playerID == playerID) {
31
pos.x = bean->stillPos.x;
32
pos.y = bean->stillPos.y;
33
}
34
}
35
36
return pos;
37
}
38
39
void PuyoAI_PrepareAction(int32 playerID)
40
{
41
EntityPuyoBean *bean = NULL;
42
EntityPuyoBean *partner = NULL;
43
44
foreach_all(PuyoBean, beanPtr)
45
{
46
if (beanPtr->stateInput && beanPtr->state == PuyoBean_State_Controlled && beanPtr->playerID == playerID) {
47
bean = beanPtr;
48
partner = bean->partner;
49
}
50
}
51
52
int32 lastBeanY = PuyoAI->lastBeanY[playerID];
53
int32 beanPos = MIN(bean->stillPos.y, partner->stillPos.y);
54
PuyoAI->lastBeanY[playerID] = beanPos;
55
56
if (lastBeanY > beanPos) {
57
uint8 columnHeights[PUYO_PLAYFIELD_W];
58
memset(columnHeights, 0, sizeof(columnHeights));
59
60
for (int32 x = 0; x < PUYO_PLAYFIELD_W; ++x) columnHeights[x] = (PUYO_PLAYFIELD_H - 1) - PuyoBean_GetColumnHeight(playerID, x, bean, partner);
61
62
beanPos = MAX(bean->stillPos.y, partner->stillPos.y);
63
64
int32 startX = MIN(bean->stillPos.x, partner->stillPos.x);
65
int32 endX = MAX(bean->stillPos.x, partner->stillPos.x);
66
67
while ((bean->stillPos.x == startX || partner->stillPos.x == startX || columnHeights[startX] > beanPos) && startX > 0) startX--;
68
69
while ((bean->stillPos.x == endX || partner->stillPos.x == endX || columnHeights[endX] > beanPos) && endX < PUYO_PLAYFIELD_W) endX++;
70
71
int32 lastY = 0;
72
int32 beanX = 0;
73
int32 beanY = 0;
74
int32 partnerX = 0;
75
int32 partnerY = 0;
76
77
for (int32 x = startX + 1; x < endX; ++x) {
78
for (int32 orientation = 0; orientation < 4; ++orientation) {
79
switch (orientation) {
80
case 0: // Oriented Left
81
if (x >= (PUYO_PLAYFIELD_W - 1))
82
continue;
83
84
beanX = x;
85
beanY = columnHeights[x];
86
partnerX = x + 1;
87
partnerY = columnHeights[x + 1];
88
break;
89
90
case 1: // Oriented Up
91
beanX = x;
92
beanY = columnHeights[x] - 1;
93
partnerX = x;
94
partnerY = columnHeights[x];
95
break;
96
97
case 2: // Oriented Right
98
if (bean->type == partner->type || x >= (PUYO_PLAYFIELD_W - 1))
99
continue;
100
101
beanX = x + 1;
102
beanY = columnHeights[x + 1];
103
partnerX = x;
104
partnerY = columnHeights[x];
105
break;
106
107
case 3: // Oriented Down
108
beanX = x;
109
beanY = columnHeights[x];
110
partnerX = x;
111
partnerY = columnHeights[x] - 1;
112
break;
113
114
default: break;
115
}
116
117
if (beanX < PUYO_PLAYFIELD_W && beanY < PUYO_PLAYFIELD_H && partnerX < PUYO_PLAYFIELD_W && partnerY < PUYO_PLAYFIELD_H) {
118
int32 chainComboSize = PuyoAI_GetChainComboSize(playerID, bean, partner, beanX, beanY, partnerX, partnerY);
119
if (chainComboSize < 16) {
120
if (!beanY && (beanX == 2 || beanX == 3))
121
chainComboSize = -1;
122
123
if (!partnerY && (partnerX == 2 || partnerX == 3))
124
chainComboSize = -1;
125
}
126
127
int32 beanAvailableLinks = PuyoBean_GetAvailableLinks(playerID, bean, beanX, beanY);
128
int32 partnerAvailableLinks = PuyoBean_GetAvailableLinks(playerID, partner, partnerX, partnerY);
129
130
int32 linkCount = (beanAvailableLinks > 0) + (partnerAvailableLinks > 0);
131
132
if (orientation == 1 || orientation == 3)
133
chainComboSize = (0x70000 * chainComboSize) >> 19;
134
135
for (; linkCount; --linkCount) chainComboSize = (0x30000 * chainComboSize) >> 18;
136
137
int32 newBeanY = (chainComboSize * ((MIN(beanY, partnerY) << 16) / 4 + 1)) >> 16;
138
if (newBeanY > lastY || (newBeanY == lastY && RSDK.Rand(0, 10) > 5)) {
139
lastY = newBeanY;
140
PuyoAI->desiredColumn[playerID] = beanX;
141
PuyoAI->desiredRotation[playerID] = orientation;
142
}
143
}
144
}
145
}
146
}
147
}
148
149
int32 PuyoAI_GetChainComboSize(int32 playerID, EntityPuyoBean *bean, EntityPuyoBean *partner, int32 beanX, int32 beanY, int32 partnerX,
150
int32 partnerY)
151
{
152
for (int32 i = 0; i < (PUYO_PLAYFIELD_W * PUYO_PLAYFIELD_H); ++i) PuyoBean->beanLinkTable[i] = false;
153
154
int32 removeCount = PuyoBean_GetBeanChainRemovalCount(playerID, bean, beanX, beanY);
155
int32 partnerRemoveCount = PuyoBean_GetBeanChainRemovalCount(playerID, partner, partnerX, partnerY);
156
157
if (bean->type == partner->type && (beanX == partnerX || beanY == partnerY))
158
return 1 << (removeCount + partnerRemoveCount);
159
else
160
return (1 << removeCount) + (1 << partnerRemoveCount);
161
}
162
163
void PuyoAI_SetupInputs(EntityPuyoBean *bean, bool32 rotationDisabled)
164
{
165
bean->down = RSDK.Rand(0, 6) > 3;
166
167
if (((bean->position.x - bean->origin.x) & 0xFFF00000) == 0x200000) {
168
if (RSDK.Rand(0, 2)) {
169
bean->left = false;
170
bean->right = true;
171
}
172
else {
173
bean->left = true;
174
bean->right = false;
175
}
176
}
177
else {
178
bean->left = RSDK.Rand(0, 2);
179
bean->right = RSDK.Rand(0, 2);
180
}
181
182
if (!rotationDisabled) {
183
bean->rotateRight = RSDK.Rand(0, 6) > 3;
184
bean->rotateLeft = RSDK.Rand(0, 6) > 3;
185
}
186
187
if (bean->left && bean->right) {
188
bean->left = false;
189
bean->right = false;
190
}
191
}
192
193
void PuyoAI_Input_AI(void)
194
{
195
RSDK_THIS(PuyoBean);
196
197
EntityPuyoBean *partner = self->partner;
198
199
self->left = false;
200
self->right = false;
201
self->rotateLeft = false;
202
self->rotateRight = false;
203
204
if (PuyoAI->isAI[self->playerID]) {
205
bool32 canMove = false;
206
bool32 canRotate = false;
207
if (PuyoAI->controlInterval[self->playerID]) {
208
canMove = !(RSDK.Rand(0, 1024) % PuyoAI->controlInterval[self->playerID]);
209
canRotate = !(Zone->timer % (4 * PuyoAI->controlInterval[self->playerID]));
210
}
211
else {
212
canMove = true;
213
canRotate = true;
214
}
215
216
if (canMove || canRotate) {
217
Vector2 beanPos = PuyoAI_GetBeanPos(self->playerID);
218
if (beanPos.x >= 0 || beanPos.y >= 0) {
219
bool32 rotationDisabled = PuyoBean_CheckAIRotationDisabled(self);
220
if (RSDK.Rand(0, 100) < PuyoAI->controlChance[self->playerID]) {
221
PuyoAI_SetupInputs(self, rotationDisabled);
222
}
223
else {
224
PuyoAI_PrepareAction(self->playerID);
225
226
uint8 currentRotation = 0;
227
if (self->stillPos.y == partner->stillPos.y && self->stillPos.x >= partner->stillPos.x) {
228
if (self->stillPos.y == partner->stillPos.y && self->stillPos.x > partner->stillPos.x) {
229
currentRotation = 2;
230
}
231
}
232
233
if (currentRotation != 2 && self->stillPos.x == partner->stillPos.x) {
234
if (self->stillPos.y >= partner->stillPos.y) {
235
if (self->stillPos.x == partner->stillPos.x && self->stillPos.y > partner->stillPos.y)
236
currentRotation = 3;
237
}
238
else {
239
currentRotation = 1;
240
}
241
}
242
243
int32 targetRotation = PuyoAI->desiredRotation[self->playerID] - currentRotation;
244
if (targetRotation == 3)
245
targetRotation = -1;
246
247
if (canRotate) {
248
if ((rotationDisabled && targetRotation == 2) || (!rotationDisabled && targetRotation > 0)) {
249
self->rotateLeft = true;
250
canMove = false;
251
}
252
else if (!rotationDisabled && targetRotation < 0) {
253
self->rotateRight = true;
254
canMove = false;
255
}
256
}
257
258
if (canMove) {
259
self->left = beanPos.x > PuyoAI->desiredColumn[self->playerID];
260
self->right = beanPos.x < PuyoAI->desiredColumn[self->playerID];
261
262
if (!targetRotation && !self->left && !self->right && beanPos.x == PuyoAI->desiredColumn[self->playerID])
263
self->down = true;
264
else
265
self->down = false;
266
}
267
}
268
}
269
}
270
}
271
}
272
273
#if GAME_INCLUDE_EDITOR
274
void PuyoAI_EditorDraw(void) {}
275
276
void PuyoAI_EditorLoad(void) {}
277
#endif
278
279
void PuyoAI_Serialize(void) {}
280
281