Path: blob/master/SonicMania/Objects/Puyo/PuyoAI.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: PuyoAI Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectPuyoAI *PuyoAI;1011void PuyoAI_Update(void) {}1213void PuyoAI_LateUpdate(void) {}1415void PuyoAI_StaticUpdate(void) {}1617void PuyoAI_Draw(void) {}1819void PuyoAI_Create(void *data) {}2021void PuyoAI_StageLoad(void) {}2223Vector2 PuyoAI_GetBeanPos(int32 playerID)24{25Vector2 pos = { -1, -1 };2627foreach_all(PuyoBean, bean)28{29if (bean->stateInput && bean->state == PuyoBean_State_Controlled && bean->playerID == playerID) {30pos.x = bean->stillPos.x;31pos.y = bean->stillPos.y;32}33}3435return pos;36}3738void PuyoAI_PrepareAction(int32 playerID)39{40EntityPuyoBean *bean = NULL;41EntityPuyoBean *partner = NULL;4243foreach_all(PuyoBean, beanPtr)44{45if (beanPtr->stateInput && beanPtr->state == PuyoBean_State_Controlled && beanPtr->playerID == playerID) {46bean = beanPtr;47partner = bean->partner;48}49}5051int32 lastBeanY = PuyoAI->lastBeanY[playerID];52int32 beanPos = MIN(bean->stillPos.y, partner->stillPos.y);53PuyoAI->lastBeanY[playerID] = beanPos;5455if (lastBeanY > beanPos) {56uint8 columnHeights[PUYO_PLAYFIELD_W];57memset(columnHeights, 0, sizeof(columnHeights));5859for (int32 x = 0; x < PUYO_PLAYFIELD_W; ++x) columnHeights[x] = (PUYO_PLAYFIELD_H - 1) - PuyoBean_GetColumnHeight(playerID, x, bean, partner);6061beanPos = MAX(bean->stillPos.y, partner->stillPos.y);6263int32 startX = MIN(bean->stillPos.x, partner->stillPos.x);64int32 endX = MAX(bean->stillPos.x, partner->stillPos.x);6566while ((bean->stillPos.x == startX || partner->stillPos.x == startX || columnHeights[startX] > beanPos) && startX > 0) startX--;6768while ((bean->stillPos.x == endX || partner->stillPos.x == endX || columnHeights[endX] > beanPos) && endX < PUYO_PLAYFIELD_W) endX++;6970int32 lastY = 0;71int32 beanX = 0;72int32 beanY = 0;73int32 partnerX = 0;74int32 partnerY = 0;7576for (int32 x = startX + 1; x < endX; ++x) {77for (int32 orientation = 0; orientation < 4; ++orientation) {78switch (orientation) {79case 0: // Oriented Left80if (x >= (PUYO_PLAYFIELD_W - 1))81continue;8283beanX = x;84beanY = columnHeights[x];85partnerX = x + 1;86partnerY = columnHeights[x + 1];87break;8889case 1: // Oriented Up90beanX = x;91beanY = columnHeights[x] - 1;92partnerX = x;93partnerY = columnHeights[x];94break;9596case 2: // Oriented Right97if (bean->type == partner->type || x >= (PUYO_PLAYFIELD_W - 1))98continue;99100beanX = x + 1;101beanY = columnHeights[x + 1];102partnerX = x;103partnerY = columnHeights[x];104break;105106case 3: // Oriented Down107beanX = x;108beanY = columnHeights[x];109partnerX = x;110partnerY = columnHeights[x] - 1;111break;112113default: break;114}115116if (beanX < PUYO_PLAYFIELD_W && beanY < PUYO_PLAYFIELD_H && partnerX < PUYO_PLAYFIELD_W && partnerY < PUYO_PLAYFIELD_H) {117int32 chainComboSize = PuyoAI_GetChainComboSize(playerID, bean, partner, beanX, beanY, partnerX, partnerY);118if (chainComboSize < 16) {119if (!beanY && (beanX == 2 || beanX == 3))120chainComboSize = -1;121122if (!partnerY && (partnerX == 2 || partnerX == 3))123chainComboSize = -1;124}125126int32 beanAvailableLinks = PuyoBean_GetAvailableLinks(playerID, bean, beanX, beanY);127int32 partnerAvailableLinks = PuyoBean_GetAvailableLinks(playerID, partner, partnerX, partnerY);128129int32 linkCount = (beanAvailableLinks > 0) + (partnerAvailableLinks > 0);130131if (orientation == 1 || orientation == 3)132chainComboSize = (0x70000 * chainComboSize) >> 19;133134for (; linkCount; --linkCount) chainComboSize = (0x30000 * chainComboSize) >> 18;135136int32 newBeanY = (chainComboSize * ((MIN(beanY, partnerY) << 16) / 4 + 1)) >> 16;137if (newBeanY > lastY || (newBeanY == lastY && RSDK.Rand(0, 10) > 5)) {138lastY = newBeanY;139PuyoAI->desiredColumn[playerID] = beanX;140PuyoAI->desiredRotation[playerID] = orientation;141}142}143}144}145}146}147148int32 PuyoAI_GetChainComboSize(int32 playerID, EntityPuyoBean *bean, EntityPuyoBean *partner, int32 beanX, int32 beanY, int32 partnerX,149int32 partnerY)150{151for (int32 i = 0; i < (PUYO_PLAYFIELD_W * PUYO_PLAYFIELD_H); ++i) PuyoBean->beanLinkTable[i] = false;152153int32 removeCount = PuyoBean_GetBeanChainRemovalCount(playerID, bean, beanX, beanY);154int32 partnerRemoveCount = PuyoBean_GetBeanChainRemovalCount(playerID, partner, partnerX, partnerY);155156if (bean->type == partner->type && (beanX == partnerX || beanY == partnerY))157return 1 << (removeCount + partnerRemoveCount);158else159return (1 << removeCount) + (1 << partnerRemoveCount);160}161162void PuyoAI_SetupInputs(EntityPuyoBean *bean, bool32 rotationDisabled)163{164bean->down = RSDK.Rand(0, 6) > 3;165166if (((bean->position.x - bean->origin.x) & 0xFFF00000) == 0x200000) {167if (RSDK.Rand(0, 2)) {168bean->left = false;169bean->right = true;170}171else {172bean->left = true;173bean->right = false;174}175}176else {177bean->left = RSDK.Rand(0, 2);178bean->right = RSDK.Rand(0, 2);179}180181if (!rotationDisabled) {182bean->rotateRight = RSDK.Rand(0, 6) > 3;183bean->rotateLeft = RSDK.Rand(0, 6) > 3;184}185186if (bean->left && bean->right) {187bean->left = false;188bean->right = false;189}190}191192void PuyoAI_Input_AI(void)193{194RSDK_THIS(PuyoBean);195196EntityPuyoBean *partner = self->partner;197198self->left = false;199self->right = false;200self->rotateLeft = false;201self->rotateRight = false;202203if (PuyoAI->isAI[self->playerID]) {204bool32 canMove = false;205bool32 canRotate = false;206if (PuyoAI->controlInterval[self->playerID]) {207canMove = !(RSDK.Rand(0, 1024) % PuyoAI->controlInterval[self->playerID]);208canRotate = !(Zone->timer % (4 * PuyoAI->controlInterval[self->playerID]));209}210else {211canMove = true;212canRotate = true;213}214215if (canMove || canRotate) {216Vector2 beanPos = PuyoAI_GetBeanPos(self->playerID);217if (beanPos.x >= 0 || beanPos.y >= 0) {218bool32 rotationDisabled = PuyoBean_CheckAIRotationDisabled(self);219if (RSDK.Rand(0, 100) < PuyoAI->controlChance[self->playerID]) {220PuyoAI_SetupInputs(self, rotationDisabled);221}222else {223PuyoAI_PrepareAction(self->playerID);224225uint8 currentRotation = 0;226if (self->stillPos.y == partner->stillPos.y && self->stillPos.x >= partner->stillPos.x) {227if (self->stillPos.y == partner->stillPos.y && self->stillPos.x > partner->stillPos.x) {228currentRotation = 2;229}230}231232if (currentRotation != 2 && self->stillPos.x == partner->stillPos.x) {233if (self->stillPos.y >= partner->stillPos.y) {234if (self->stillPos.x == partner->stillPos.x && self->stillPos.y > partner->stillPos.y)235currentRotation = 3;236}237else {238currentRotation = 1;239}240}241242int32 targetRotation = PuyoAI->desiredRotation[self->playerID] - currentRotation;243if (targetRotation == 3)244targetRotation = -1;245246if (canRotate) {247if ((rotationDisabled && targetRotation == 2) || (!rotationDisabled && targetRotation > 0)) {248self->rotateLeft = true;249canMove = false;250}251else if (!rotationDisabled && targetRotation < 0) {252self->rotateRight = true;253canMove = false;254}255}256257if (canMove) {258self->left = beanPos.x > PuyoAI->desiredColumn[self->playerID];259self->right = beanPos.x < PuyoAI->desiredColumn[self->playerID];260261if (!targetRotation && !self->left && !self->right && beanPos.x == PuyoAI->desiredColumn[self->playerID])262self->down = true;263else264self->down = false;265}266}267}268}269}270}271272#if GAME_INCLUDE_EDITOR273void PuyoAI_EditorDraw(void) {}274275void PuyoAI_EditorLoad(void) {}276#endif277278void PuyoAI_Serialize(void) {}279280281