Path: blob/master/SonicMania/Objects/PGZ/PaperRoller.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: PaperRoller Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectPaperRoller *PaperRoller;1011void PaperRoller_Update(void)12{13RSDK_THIS(PaperRoller);1415RSDK.ProcessAnimation(&self->rollerAnimator);1617int32 startX = self->position.x - (RSDK.Cos256(self->angle) << 7) * self->length;18int32 startY = self->position.y - (RSDK.Sin256(self->angle) << 7) * self->length;19int32 endX = self->position.x + (RSDK.Cos256(self->angle) << 7) * self->length;20int32 endY = self->position.y + (RSDK.Sin256(self->angle) << 7) * self->length;21int32 centerX = self->position.x;22int32 centerY = self->position.y;2324// left roller25self->position.x = startX;26self->position.y = startY;27PaperRoller_HandleRollerCollisions();2829// right roller30self->position.x = endX;31self->position.y = endY;32PaperRoller_HandleRollerCollisions();333435self->position.x = centerX;36self->position.y = centerY;37PaperRoller_HandlePrintCollisions();3839if (self->direction == FLIP_NONE)40self->divotAngle += 6;41else42self->divotAngle -= 6;4344if (self->divotAngle < 0)45self->divotAngle += 0x100;4647self->divotAngle &= 0xFF;48}4950void PaperRoller_LateUpdate(void) {}5152void PaperRoller_StaticUpdate(void) {}5354void PaperRoller_Draw(void)55{56PaperRoller_DrawPaperLines();57PaperRoller_DrawRollers();58}5960void PaperRoller_Create(void *data)61{62RSDK_THIS(PaperRoller);6364self->active = ACTIVE_BOUNDS;65self->drawGroup = Zone->objectDrawGroup[0];66self->startPos.x = self->position.x;67self->startPos.y = self->position.y;68self->visible = true;69self->drawFX = FX_NONE;70self->updateRange.x = 0x800000;71self->updateRange.y = 0x800000;7273self->updateRange.x += abs((RSDK.Cos256(self->angle) << 8) * self->length);74self->updateRange.y += abs((RSDK.Sin256(self->angle) << 8) * self->length);7576if (self->length > 256)77self->length = 256;7879self->lastJumpTimer[0] = 0x7FFF;80self->lastJumpTimer[1] = 0x7FFF;81self->lastJumpTimer[2] = 0x7FFF;82self->lastJumpTimer[3] = 0x7FFF;8384self->hitbox.left = -24;85self->hitbox.top = -24;86self->hitbox.right = 24;87self->hitbox.bottom = 24;8889RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 0, &self->rollerAnimator, true, 0);90RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 1, &self->divotAnimator, true, 0);91}9293void PaperRoller_StageLoad(void)94{9596PaperRoller->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/PaperRoller.bin", SCOPE_STAGE);9798color colors[] = { 0x0F0F0E8, 0x0D0B898, 0x987870, 0x586868 };99for (int32 i = 0; i < 0x40; ++i) PaperRoller->colors[i] = colors[i & 3];100101PaperRoller->sfxPaper = RSDK.GetSfx("PSZ/Paper.wav");102}103104void PaperRoller_DrawDeformedLine(int32 startX, int32 startY, int32 endX, int32 endY, int32 offsetX, int32 offsetY, int32 deformX, int32 deformY,105int32 len, uint32 *color)106{107RSDK_THIS(PaperRoller);108109int32 count = (self->length / 4) + ((self->length % 4) > 0);110if (count) {111int32 negAngle = -self->angle & 0xFF;112113int32 currentX = startX;114int32 currentY = startY;115int32 moveX = (endX - startX) / count;116int32 moveY = (endY - startY) / count;117118for (int32 i = 0; i < count; ++i) {119int32 colorID = self->direction ? (len % count) : (count - len % count - 1);120121uint32 lineColor = color ? *color : PaperRoller->colors[(Zone->timer + colorID) % count];122123if (!deformY) {124RSDK.DrawLine(offsetX + currentX, offsetY + currentY, offsetX + (currentX + moveX), offsetY + (currentY + moveY), lineColor, 0x7F,125INK_NONE, false);126}127else {128int32 distX = (currentX - self->position.x) >> 8;129int32 distY = (currentY - self->position.y) >> 8;130131int32 angValX = distY * RSDK.Sin256(self->angle) + distX * RSDK.Cos256(self->angle);132int32 angValY = self->position.y - distX * RSDK.Sin256(self->angle) + distY * RSDK.Cos256(self->angle) - self->position.y;133134int32 lenY = 0;135136if (angValX >= deformX) {137int32 length = abs((self->length << 15) - deformX);138139if (length >> 16 > 0)140lenY = (deformY >> 8) * ((length + deformX - angValX) >> 8) / (length >> 16);141}142else {143int32 length = length = abs(deformX + (self->length << 15));144145if (length >> 16 > 0)146lenY = (deformY >> 8) * (((self->length << 15) + angValX) >> 8) / (length >> 16);147}148149distX = angValX >> 8;150distY = (lenY + angValY) >> 8;151152Vector2 offset1;153offset1.x = self->position.x + distY * RSDK.Sin256(negAngle) + distX * RSDK.Cos256(negAngle);154offset1.y = self->position.y - distX * RSDK.Sin256(negAngle) + distY * RSDK.Cos256(negAngle);155156distX = ((currentX + moveX) - self->position.x) >> 8;157distY = ((currentY + moveY) - self->position.y) >> 8;158159angValX = distY * RSDK.Sin256(self->angle) + distX * RSDK.Cos256(self->angle);160angValY = self->position.y - distX * RSDK.Sin256(self->angle) + distY * RSDK.Cos256(self->angle) - self->position.y;161162lenY = 0;163if (angValX >= deformX) {164int32 length = abs((self->length << 15) - deformX);165166if (length >> 16 > 0)167lenY = (deformY >> 8) * ((length + deformX - angValX) >> 8) / (length >> 16);168}169else {170int32 length = abs((self->length << 15) + deformX);171172if (length >> 16 > 0)173lenY = (deformY >> 8) * (((self->length << 15) + angValX) >> 8) / (length >> 16);174}175176distX = angValX >> 8;177distY = (lenY + angValY) >> 8;178179Vector2 offset2;180offset2.x = self->position.x + distY * RSDK.Sin256(negAngle) + distX * RSDK.Cos256(negAngle);181offset2.y = self->position.y - distX * RSDK.Sin256(negAngle) + distY * RSDK.Cos256(negAngle);182183RSDK.DrawLine(offsetX + offset1.x, offsetY + offset1.y, offsetX + offset2.x, offsetY + offset2.y, lineColor, 0x7F, INK_NONE, false);184}185186++len;187188currentX += moveX;189currentY += moveY;190}191}192}193194void PaperRoller_DrawPaperLines(void)195{196RSDK_THIS(PaperRoller);197198int32 x1 = self->position.x - (RSDK.Cos256(self->angle) << 7) * self->length;199int32 y1 = self->position.y - (RSDK.Sin256(self->angle) << 7) * self->length;200int32 x2 = self->position.x + (RSDK.Cos256(self->angle) << 7) * self->length;201int32 y2 = self->position.y + (RSDK.Sin256(self->angle) << 7) * self->length;202203int32 len = self->length / 4 + (self->length % 4 > 0);204int32 startX1 = x1 + 0x1800 * RSDK.Cos256(self->angle - 64);205int32 startY1 = y1 + 0x1800 * RSDK.Sin256(self->angle - 64);206int32 endX1 = x2 + 0x1800 * RSDK.Cos256(self->angle - 64);207int32 endY1 = y2 + 0x1800 * RSDK.Sin256(self->angle - 64);208209int32 startX2 = x2 + 0x1800 * RSDK.Cos256(self->angle + 64);210int32 startY2 = y2 + 0x1800 * RSDK.Sin256(self->angle + 64);211int32 endX2 = x1 + 0x1800 * RSDK.Cos256(self->angle + 64);212int32 endY2 = y1 + 0x1800 * RSDK.Sin256(self->angle + 64);213214PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, 0, 0, self->deformPosTop.x, self->deformPosTop.y, 0, NULL);215PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, 0, 0, self->deformPosBottom.x, self->deformPosBottom.y, len, NULL);216217int32 angle = self->angle + 32;218if (angle < 0)219angle = ((-1 - (self->angle + 32)) & 0xFFFFFF00) + self->angle + 288;220221int32 offsetY1 = 0, offsetY2 = 0, offsetX2 = 0, offsetX1 = 0;222switch (angle >> 6) {223case 0:224offsetY1 = 0x10000;225offsetY2 = -0x10000;226break;227228case 1:229offsetX1 = -0x10000;230offsetX2 = 0x10000;231break;232233case 2:234offsetY1 = -0x10000;235offsetY2 = 0x10000;236break;237238case 3:239offsetX1 = 0x10000;240offsetX2 = -0x10000;241break;242}243PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, offsetX1, offsetY1, self->deformPosTop.x, self->deformPosTop.y, 0, NULL);244PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, offsetX2, offsetY2, self->deformPosBottom.x, self->deformPosBottom.y, len, NULL);245246color color = 0xD0B898;247offsetX1 <<= 1;248offsetY1 <<= 1;249offsetX2 <<= 1;250offsetY2 <<= 1;251PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, offsetX1, offsetY1, self->deformPosTop.x, self->deformPosTop.y, 0, &color);252PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, offsetX2, offsetY2, self->deformPosBottom.x, self->deformPosBottom.y, len, &color);253}254255void PaperRoller_DrawRollers(void)256{257RSDK_THIS(PaperRoller);258259Vector2 rollerPos;260Vector2 divotPos;261262rollerPos = self->position;263rollerPos.x -= (RSDK.Cos256(self->angle) << 7) * self->length;264rollerPos.y -= (RSDK.Sin256(self->angle) << 7) * self->length;265RSDK.DrawSprite(&self->rollerAnimator, &rollerPos, false);266267divotPos = rollerPos;268divotPos.x += -0x900 * RSDK.Cos256(self->divotAngle);269divotPos.y += -0x900 * RSDK.Sin256(self->divotAngle);270RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);271272divotPos = rollerPos;273divotPos.x += 0x900 * RSDK.Cos256(self->divotAngle);274divotPos.y += 0x900 * RSDK.Sin256(self->divotAngle);275RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);276277rollerPos = self->position;278rollerPos.x += (RSDK.Cos256(self->angle) << 7) * self->length;279rollerPos.y += (RSDK.Sin256(self->angle) << 7) * self->length;280RSDK.DrawSprite(&self->rollerAnimator, &rollerPos, false);281282divotPos = rollerPos;283divotPos.x += -0x900 * RSDK.Cos256(self->divotAngle);284divotPos.y += -0x900 * RSDK.Sin256(self->divotAngle);285RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);286287divotPos = rollerPos;288divotPos.x += 0x900 * RSDK.Cos256(self->divotAngle);289divotPos.y += 0x900 * RSDK.Sin256(self->divotAngle);290RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);291}292293void PaperRoller_HandleRollerCollisions(void)294{295RSDK_THIS(PaperRoller);296297foreach_active(Player, player)298{299int32 playerID = RSDK.GetEntitySlot(player);300if (self->playerTimer[playerID] <= 0) {301int32 distX = abs(self->position.x - player->position.x) >> 16;302int32 distY = abs(self->position.y - player->position.y) >> 16;303if (MathHelpers_SquareRoot(distX * distX + distY * distY) <= 40 && !self->playerTimer[playerID]) {304RSDK.PlaySfx(Player->sfxRelease, false, 255);305int32 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y);306307int32 ang = angle + (self->direction == FLIP_NONE ? 64 : -64);308309player->position.x = self->position.x + 0x2800 * RSDK.Cos256(angle);310player->position.y = self->position.y + 0x2800 * RSDK.Sin256(angle);311player->velocity.x = RSDK.Cos256(ang) << 11;312player->velocity.y = RSDK.Sin256(ang) << 11;313player->state = Player_State_Air;314RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);315316player->nextAirState = StateMachine_None;317player->nextGroundState = StateMachine_None;318player->onGround = false;319player->groundVel = 0;320// bug details: fixes a bug where knux can touch this without tile collisions enabled lol321#if GAME_VERSION != VER_100322player->tileCollisions = TILECOLLISION_DOWN;323#endif324player->applyJumpCap = false;325player->jumpAbilityState = 0;326327self->playerTimer[playerID] = 10;328}329}330else {331self->playerTimer[playerID]--;332}333}334}335336void PaperRoller_HandlePrintCollisions(void)337{338RSDK_THIS(PaperRoller);339340bool32 hasDeformedTop = false;341bool32 hasDeformedBottom = false;342343int32 negAngle = -self->angle;344self->deformPosTop.x = 0;345self->deformPosTop.y = 0;346self->deformPosBottom.x = 0;347self->deformPosBottom.y = 0;348349foreach_active(Player, player)350{351int32 playerID = RSDK.GetEntitySlot(player);352353if (player->jumpPress)354self->lastJumpTimer[playerID] = 0;355else356++self->lastJumpTimer[playerID];357358Vector2 pivotPos = player->position;359Zone_RotateOnPivot(&pivotPos, &self->position, self->angle);360361int32 pivotX = pivotPos.x - self->position.x;362int32 pivotY = pivotPos.y - self->position.y;363364if (abs(pivotX) <= self->length << 15 && abs(pivotY) <= 0x280000) {365int32 deformY = 0;366if (pivotY < 0) {367if (abs(pivotY) > 0x180000) {368deformY = pivotY + 0x280000;369}370else {371Vector2 playerPos;372playerPos.x = self->position.x + pivotX;373playerPos.y = self->position.y - 0x180000;374Zone_RotateOnPivot(&playerPos, &self->position, negAngle);375376Vector2 pivotPos = { 0, 0 };377player->position = playerPos;378379Vector2 playerVel = player->velocity;380Zone_RotateOnPivot(&playerVel, &pivotPos, self->angle);381int32 angle = RSDK.ATan2(playerVel.x, -playerVel.y);382383int32 force = player->jumpHold ? 12 : 6;384385playerVel.x = force * (RSDK.Cos256(angle) << 8);386playerVel.y = force * (RSDK.Sin256(angle) << 8);387if (abs(playerVel.x) < 0x10000)388playerVel.x += ((2 * (self->direction == FLIP_NONE) - 1) << 16);389390Zone_RotateOnPivot(&playerVel, &pivotPos, negAngle);391player->velocity = playerVel;392393player->state = Player_State_Air;394RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);395396player->nextAirState = StateMachine_None;397player->nextGroundState = StateMachine_None;398player->onGround = false;399player->groundVel = 0;400// bug details: fixes a bug where knux can touch this without tile collisions enabled lol401#if GAME_VERSION != VER_100402player->tileCollisions = TILECOLLISION_DOWN;403#endif404player->applyJumpCap = false;405player->jumpAbilityState = 0;406RSDK.PlaySfx(PaperRoller->sfxPaper, false, 0xFF);407408deformY = 0x100000;409}410411if (player->sidekick) {412if (!hasDeformedTop) {413self->deformPosTop.x = pivotX;414self->deformPosTop.y = deformY;415}416}417else {418self->deformPosTop.x = pivotX;419self->deformPosTop.y = deformY;420hasDeformedTop = true;421}422}423else {424if (abs(pivotY) > 0x180000) {425deformY = pivotY - 0x280000;426}427else {428Vector2 playerPos;429playerPos.x = self->position.x + pivotX;430playerPos.y = self->position.y + 0x180000;431Zone_RotateOnPivot(&playerPos, &self->position, negAngle);432433Vector2 pivotPos = { 0, 0 };434player->position = playerPos;435436Vector2 playerVel = player->velocity;437Zone_RotateOnPivot(&playerVel, &pivotPos, self->angle);438439int32 angle = RSDK.ATan2(playerVel.x, -playerVel.y);440int32 force = player->jumpHold ? 12 : 6;441442playerVel.x = force * (RSDK.Cos256(angle) << 8);443playerVel.y = force * (RSDK.Sin256(angle) << 8);444if ((self->direction == FLIP_NONE && playerVel.x > -0x10000) || (self->direction == FLIP_X && playerVel.x < 0x10000))445playerVel.x += ((2 * (self->direction != FLIP_NONE) - 1) << 18);446447Zone_RotateOnPivot(&playerVel, &pivotPos, negAngle);448player->velocity = playerVel;449450player->state = Player_State_Air;451RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);452453player->nextAirState = StateMachine_None;454player->nextGroundState = StateMachine_None;455player->onGround = false;456player->groundVel = 0;457// bug details: fixes a bug where knux can touch this without tile collisions enabled lol458#if GAME_VERSION != VER_100459player->tileCollisions = TILECOLLISION_DOWN;460#endif461player->applyJumpCap = false;462player->jumpAbilityState = 0;463RSDK.PlaySfx(PaperRoller->sfxPaper, false, 0xFF);464465deformY = -0x100000;466}467468if (!player->sidekick) {469self->deformPosBottom.x = pivotX;470self->deformPosBottom.y = deformY;471hasDeformedBottom = true;472}473else if (!hasDeformedBottom) {474self->deformPosBottom.x = pivotX;475self->deformPosBottom.y = deformY;476}477}478}479}480}481482#if GAME_INCLUDE_EDITOR483void PaperRoller_EditorDraw(void)484{485RSDK_THIS(PaperRoller);486487self->drawGroup = Zone->objectDrawGroup[0];488self->startPos = self->position;489self->visible = true;490self->drawFX = FX_NONE;491self->updateRange.x = 0x800000;492self->updateRange.y = 0x800000;493494int32 len = self->length;495496self->updateRange.x += abs((RSDK.Cos256(self->angle) << 8) * self->length);497self->updateRange.y += abs((RSDK.Sin256(self->angle) << 8) * self->length);498499if (self->length > 256)500self->length = 256;501502RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 0, &self->rollerAnimator, true, 0);503RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 1, &self->divotAnimator, true, 0);504505PaperRoller_DrawPaperLines();506PaperRoller_DrawRollers();507508self->length = len;509}510511void PaperRoller_EditorLoad(void)512{513PaperRoller_StageLoad();514515RSDK_ACTIVE_VAR(PaperRoller, direction);516RSDK_ENUM_VAR("Right", FLIP_NONE);517RSDK_ENUM_VAR("Left", FLIP_X);518}519#endif520521void PaperRoller_Serialize(void)522{523RSDK_EDITABLE_VAR(PaperRoller, VAR_UINT8, direction);524RSDK_EDITABLE_VAR(PaperRoller, VAR_ENUM, length);525RSDK_EDITABLE_VAR(PaperRoller, VAR_ENUM, angle);526}527528529