00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "Player.h"
00026
00027 #include <gcmodplay.h>
00028 #include "libwiigui/gui.h"
00029 #include "Options.h"
00030 #include "tcyc_menu.h"
00031 #include "main.h"
00032
00033 extern MODPlay g_modPlay;
00034 extern GuiSound *g_tetrisCheerSound;
00035 extern Options *g_options;
00036 extern Player *g_players;
00037 extern GXRModeObj *g_vmode;
00038 extern Mtx g_view;
00039 extern bool g_isClassicMode;
00040
00041
00042 void Player::Reset()
00043 {
00044 memset(&gameData, 0, sizeof(PlayerGameData));
00045 gameData.pieces = -1;
00046 gameData.speed = START_SPEED;
00047
00048 for (int y = 0; y < MAX_PLAYFIELD_HEIGHT; ++y)
00049 {
00050 for (int x = 0; x < MAX_PLAYFIELD_WIDTH; ++x)
00051 gameData.playfield[x][y].pieceId = TETRISPIECE_ID_NONE;
00052 }
00053
00054 nextPiece.InitPiece(TetrisPiece::GetNextId());
00055 nextPiece.SetPowerupId(PowerupUtils::GetNextId(*this));
00056 _SpawnNextPiece();
00057
00058 PowerupId *tmpPowerupStartQueue = !isHandicapEnabled ?
00059 g_options->profile.powerupStartQueue : profile.powerupStartQueue;
00060
00061 for (int i = 0; i < MAX_ACQUIRED_POWERUPS; ++i)
00062 {
00063 PowerupId pid = tmpPowerupStartQueue[i];
00064 if (pid != POWERUP_ID_NONE)
00065 gameData.powerupQueue[i] = PowerupUtils::GetStaticInstance(pid);
00066 }
00067 }
00068
00069
00070 void Player::DrawPlayfield()
00071 {
00072 TetrisPieceConnectivityInfo *connectivityInfo = NULL;
00073 GuiImageData *imgData = NULL;
00074
00075 for (int y = 0; y < playfieldHeight; ++y)
00076 {
00077 for (int x = 0; x < playfieldWidth; ++x)
00078 {
00079 TetrisPieceId pieceId = gameData.playfield[x][y].pieceId;
00080 if (pieceId == TETRISPIECE_ID_NONE)
00081 continue;
00082
00083 ColorId gfx = (ColorId)pieceId;
00084
00085 if (gameData.isDead)
00086 {
00087 gfx = COLOR_ID_DEAD;
00088 }
00089 else
00090 {
00091 connectivityInfo = gameData.playfield[x][y].connectivityInfo;
00092 imgData = !connectivityInfo ?
00093 NULL : PowerupUtils::GetImageData(connectivityInfo->powerupId);
00094 }
00095
00096 DrawBlockAsCube(x, y, gfx, 255, imgData);
00097 }
00098 }
00099 }
00100
00101
00102 void Player::DrawPiece(TetrisPiece* cp, u8 alpha)
00103 {
00104 TetrisPiece &piece = !cp ? currPiece : *cp;
00105 const TetrisPieceDesc &desc = piece.GetPieceDescription();
00106
00107 ColorId gfx = (ColorId)piece.GetPieceId();
00108 GuiImageData *imgData = (piece.GetPowerupId() == POWERUP_ID_NONE) ?
00109 NULL : PowerupUtils::GetImageData(piece.GetPowerupId());
00110
00111 if (gameData.isDead)
00112 {
00113 gfx = COLOR_ID_DEAD;
00114 imgData = NULL;
00115 }
00116
00117
00118 for (int y = 0; y < 4; ++y)
00119 {
00120 for (int x = 0; x < 4; ++x)
00121 {
00122
00123
00124
00125
00126
00127
00128 int calcx = piece.GetX() + x;
00129 int calcy = piece.GetY() + y;
00130
00131
00132 if (calcx >= playfieldWidth)
00133 calcx -= playfieldWidth;
00134 else if (calcx < 0)
00135 calcx += playfieldWidth;
00136
00137 if (desc.map[x][y] && calcx >= 0 && calcy >= 0)
00138 DrawBlockAsCube(calcx, calcy, gfx, alpha, imgData);
00139 }
00140 }
00141 }
00142
00143
00144 void Player::DrawPieceShadow()
00145 {
00146 if (guide == GUIDE_OFF)
00147 return;
00148
00149 int y = 0;
00150 if (guide == GUIDE_SHADOW)
00151 {
00152
00153
00154
00155 TetrisPiece piece = currPiece;
00156 y = piece.GetY();
00157 while (MovePiece(DOWN, &piece));
00158 if (y < 7 && piece.GetY() > 11)
00159 DrawPiece(&piece, 145);
00160
00161 return;
00162 }
00163
00164
00165 int x = 0;
00166 const TetrisPieceDesc &desc = currPiece.GetPieceDescription();
00167
00168
00169 for (int my = 0; my < 4; ++my)
00170 {
00171 for (int mx = 0; mx < 4; ++mx)
00172 {
00173 if (desc.map[mx][my])
00174 {
00175 x = currPiece.GetX() + mx;
00176 y = currPiece.GetY() + my + 1;
00177 break;
00178 }
00179 }
00180 }
00181
00182 if (x < 0)
00183 x += playfieldWidth;
00184 else if (x >= playfieldWidth)
00185 x -= playfieldWidth;
00186
00187 for (; y < playfieldHeight; ++y)
00188 {
00189 if (gameData.playfield[x][y].pieceId == TETRISPIECE_ID_NONE)
00190 DrawBlockAsCube(x, y, COLOR_ID_RED, 128, NULL, true);
00191 }
00192 }
00193
00194
00195 void Player::DrawBase()
00196 {
00197 GXColor color;
00198
00199 for (int x = 0; x < playfieldWidth; ++x)
00200 {
00201 int idx = (x + gameData.cycleIdx) % playfieldWidth;
00202 u8 c = idx * 8;
00203 color = (GXColor){c, c, c, 255};
00204 _SetBaseColor(color);
00205 DrawBlockAsCube(x, playfieldHeight, COLOR_ID_BASE);
00206 }
00207 }
00208
00209
00210 bool Player::MovePlayfield(int type)
00211 {
00212 TetrisPiece &piece = currPiece;
00213
00214 int oldx = piece.GetX();
00215 int x = oldx;
00216
00217
00218
00219 switch (type)
00220 {
00221 case RIGHT:
00222 --x;
00223 if (x < 0)
00224 x += playfieldWidth;
00225 piece.SetX(x);
00226 break;
00227
00228 case LEFT:
00229 ++x;
00230 if (x >= playfieldWidth)
00231 x -= playfieldWidth;
00232 piece.SetX(x);
00233 break;
00234 }
00235
00236 bool canPlace = _CanPlacePiece();
00237
00238
00239 piece.SetX(oldx);
00240
00241 if (!canPlace)
00242 return false;
00243
00244
00245 TetrisPieceBlock *playfieldTPB = &gameData.playfield[0][0];
00246 TetrisPieceBlock tmpTPB;
00247 TetrisPieceBlock *prevTPB, *currTPB;
00248
00249 if (type == LEFT)
00250 {
00251 for (int r = 0; r < playfieldHeight; ++r)
00252 {
00253 prevTPB = playfieldTPB + r;
00254 currTPB = prevTPB + MAX_PLAYFIELD_HEIGHT;
00255 tmpTPB = *prevTPB;
00256
00257 for (int c = 0; c < playfieldWidth - 1; ++c, prevTPB += MAX_PLAYFIELD_HEIGHT, currTPB += MAX_PLAYFIELD_HEIGHT)
00258 *prevTPB = *currTPB;
00259
00260 *prevTPB = tmpTPB;
00261 }
00262 }
00263 else if (type == RIGHT)
00264 {
00265 for (int r = 0; r < playfieldHeight; ++r)
00266 {
00267 prevTPB = playfieldTPB + (playfieldWidth - 1) * MAX_PLAYFIELD_HEIGHT + r;
00268 currTPB = prevTPB - MAX_PLAYFIELD_HEIGHT;
00269 tmpTPB = *prevTPB;
00270
00271 for (int c = 0; c < playfieldWidth - 1; ++c, prevTPB -= MAX_PLAYFIELD_HEIGHT, currTPB -= MAX_PLAYFIELD_HEIGHT)
00272 *prevTPB = *currTPB;
00273
00274 *prevTPB = tmpTPB;
00275 }
00276 }
00277
00278 return true;
00279 }
00280
00281
00282 bool Player::MovePiece(int type, TetrisPiece *cp)
00283 {
00284 TetrisPiece &piece = !cp ? currPiece : *cp;
00285
00286 int oldx = piece.GetX();
00287 int oldy = piece.GetY();
00288 int x = oldx;
00289
00290 switch (type)
00291 {
00292 case DOWN:
00293 piece.SetY(oldy + 1);
00294 break;
00295
00296 case LEFT:
00297 --x;
00298 if (!g_isClassicMode && x < 0)
00299 x += playfieldWidth;
00300 piece.SetX(x);
00301 break;
00302
00303 case RIGHT:
00304 ++x;
00305 if (!g_isClassicMode && x >= playfieldWidth)
00306 x -= playfieldWidth;
00307 piece.SetX(x);
00308 break;
00309 }
00310
00311 if (_CanPlacePiece(&piece))
00312 return true;
00313
00314 piece.SetX(oldx);
00315 piece.SetY(oldy);
00316 return false;
00317 }
00318
00319
00320 void Player::DoMovement()
00321 {
00322 const TetrisPieceDesc &desc = currPiece.GetPieceDescription();
00323
00324 gameData.frame = 0;
00325 currPiece.IncrementDownCounter();
00326
00327 bool canMove = MovePiece(DOWN);
00328 bool canplace = _CanPlacePiece();
00329
00330
00331 if (!canMove)
00332 {
00333 int nblocks = (currPiece.GetPieceId() != TETRISPIECE_ID_JUNK) ? DEFAULT_BLOCKS_PER_PIECE : 8;
00334 TetrisPieceConnectivityInfo *info = (currPiece.GetPowerupId() == POWERUP_ID_NONE) ?
00335 NULL : new TetrisPieceConnectivityInfo(currPiece.GetPowerupId(), nblocks);
00336
00337 for (int y = 0; y < 4; ++y)
00338 {
00339 for (int x = 0; x < 4; ++x)
00340 {
00341
00342
00343
00344
00345
00346
00347 int calcx = currPiece.GetX() + x;
00348 int calcy = currPiece.GetY() + y;
00349
00350
00351 if (calcx >= playfieldWidth)
00352 calcx -= playfieldWidth;
00353 else if (calcx < 0)
00354 calcx += playfieldWidth;
00355
00356 if (calcx >= 0 && calcx < playfieldWidth && calcy >= 0
00357 && calcy < playfieldHeight && desc.map[x][y])
00358 {
00359 gameData.playfield[calcx][calcy].pieceId = currPiece.GetPieceId();
00360 gameData.playfield[calcx][calcy].SetConnectivityInfo(info);
00361 }
00362 }
00363 }
00364 }
00365
00366
00367 if (!canMove && !canplace)
00368 {
00369 if (g_options->players == 1)
00370 {
00371 gameData.isDead = true;
00372 TCYC_MenuPause("Game Over");
00373 return;
00374 }
00375
00376 gameData.isDead = true;
00377 _GetWinner();
00378 return;
00379 }
00380
00381
00382 if (!canMove)
00383 {
00384 int linesInFrame = 0;
00385
00386 while (_RemoveLines())
00387 ++linesInFrame;
00388
00389 if (linesInFrame == 3)
00390 {
00391 gameData.score++;
00392 }
00393 else if (linesInFrame == 4)
00394 {
00395 gameData.score += 2;
00396 MODPlay_Pause(&g_modPlay, 1);
00397 g_tetrisCheerSound->Play();
00398 }
00399
00400 _SpawnNextPiece();
00401 }
00402
00403
00404
00405
00406
00407 }
00408
00409
00410 void Player::DrawBlockAsCube(float x, float y, ColorId colorIdx, u8 alpha, GuiImageData *imgData, bool isGuideDot)
00411 {
00412 float scale = _GetScale() / (float)DEFAULT_PLAYFIELD_SCALE;
00413 if (g_isClassicMode)
00414 scale -= 0.1;
00415
00416 float vx = 0;
00417
00418 if (g_options->players == 1 && !g_options->isNetplay)
00419 {
00420
00421 }
00422 else if (g_options->players == 2)
00423 {
00424 if (id == 0)
00425 vx = -106.6;
00426 else
00427 vx = 213.4;
00428 }
00429 else if (g_options->players == 3)
00430 {
00431 if (id == 0)
00432 vx = -210;
00433 else if (id == 2)
00434 vx = 210;
00435 }
00436 else if (g_options->players == 4)
00437 {
00438 if (id == 0)
00439 vx = -240;
00440 else if (id == 1)
00441 vx = -80;
00442 else if (id == 2)
00443 vx = 80;
00444 else
00445 vx = 240;
00446 }
00447
00448 GX_SetViewport(vx + playfieldDX, playfieldDY, g_vmode->fbWidth, g_vmode->efbHeight, 0, 1);
00449
00450
00451
00452
00453
00454 int centerRight = playfieldWidth >> 1;
00455 int centerLeft = centerRight - 1;
00456 int offsetFromCenter = (x > centerLeft) ? x - centerLeft : x - centerRight;
00457
00458
00459 y = ((playfieldHeight >> 1) - 1 - y) * scale;
00460
00461
00462 float hz = scale / 2;
00463
00464
00465 static Mtx mscale;
00466 guMtxIdentity(mscale);
00467 if (!isGuideDot)
00468 {
00469 guMtxScale(mscale, scale, scale, scale);
00470 }
00471 else
00472 {
00473 float dotScale = scale * 0.35;
00474 guMtxScale(mscale, dotScale, dotScale, dotScale);
00475 }
00476
00477
00478 float cubeRotation = !g_isClassicMode ? cubeAngle : 0;
00479
00480 if (offsetFromCenter < 0)
00481 {
00482 scale *= -1;
00483 cubeRotation *= -1;
00484 offsetFromCenter *= -1;
00485 }
00486
00487
00488
00489 static Mtx mtrans;
00490 guMtxIdentity(mtrans);
00491 guMtxTransApply(mtrans, mtrans, scale, 0.f, 0.f);
00492
00493
00494
00495 static guVector cubeAxis = {0, 1, 0};
00496 static Mtx mrot;
00497 guMtxIdentity(mrot);
00498 guMtxRotAxisDeg(mrot, &cubeAxis, cubeRotation);
00499
00500 static Mtx mrottrans;
00501 guMtxIdentity(mrottrans);
00502 guMtxConcat(mrot, mtrans, mrottrans);
00503
00504 static Mtx model;
00505 static Mtx modelview;
00506
00507 guMtxIdentity(model);
00508
00509 for (int i = 0; i < offsetFromCenter - 1; ++i)
00510 {
00511 guMtxConcat(model, mrottrans, model);
00512 }
00513
00514 guMtxConcat(model, mrot, model);
00515
00516
00517 static Mtx halfcubetrans;
00518 guMtxIdentity(halfcubetrans);
00519 guMtxTransApply(halfcubetrans, halfcubetrans, scale / 2, 0.f, -hz);
00520
00521 guMtxConcat(model, halfcubetrans, model);
00522 guMtxConcat(model, mscale, model);
00523
00524
00525 static Mtx trans;
00526 guMtxIdentity(trans);
00527 guMtxTransApply(trans, trans, 0, y, -32);
00528
00529 guMtxConcat(trans, model, model);
00530 guMtxConcat(g_view, model, modelview);
00531
00532
00533 GX_LoadPosMtxImm(modelview, GX_PNMTX0);
00534 GX_Cube(colorIdx, alpha, imgData);
00535 GX_SetViewport(0, 0, g_vmode->fbWidth, g_vmode->efbHeight, 0, 1);
00536 }
00537
00538
00539
00540 void Player::_GetWinner()
00541 {
00542 int ndead = 0;
00543 int winner = 0;
00544
00545 for (int i = 0; i < g_options->players; ++i)
00546 {
00547 if (g_players[i].gameData.isDead)
00548 ++ndead;
00549 else
00550 winner = i;
00551 }
00552
00553 if (ndead == g_options->players - 1)
00554 _DisplayWinner(winner);
00555 }
00556
00557 void Player::_DisplayWinner(int winner)
00558 {
00559 char buf[15];
00560 sprintf(buf, "Player %d wins!", winner + 1);
00561 TCYC_MenuPause(buf);
00562 }
00563
00564 void Player::_IncreaseLevelAllBut(int plyrIdx)
00565 {
00566 for (int i = 0; i < g_options->players; ++i)
00567 {
00568 if (i != plyrIdx)
00569 g_players[i]._IncreaseLevel();
00570 }
00571 }
00572
00573
00574 bool Player::_CanPlacePiece(TetrisPiece *cp)
00575 {
00576 TetrisPiece &piece = !cp ? currPiece : *cp;
00577 const TetrisPieceDesc &desc = piece.GetPieceDescription();
00578
00579 for (int y = 0; y < 4; y++)
00580 {
00581 for (int x = 0; x < 4; x++)
00582 {
00583
00584 if (desc.map[x][y])
00585 {
00586
00587
00588
00589
00590
00591
00592 int calcx = piece.GetX() + x;
00593 int calcy = piece.GetY() + y;
00594
00595
00596
00597
00598 if (calcx >= playfieldWidth)
00599 {
00600 if (!g_isClassicMode)
00601 calcx -= playfieldWidth;
00602 else
00603 return false;
00604 }
00605 else if (calcx < 0)
00606 {
00607 if (!g_isClassicMode)
00608 calcx += playfieldWidth;
00609 else
00610 return false;
00611 }
00612
00613 if (calcy >= playfieldHeight)
00614 return false;
00615
00616
00617 if (calcy >= 0
00618 && gameData.playfield[calcx][calcy].pieceId != TETRISPIECE_ID_NONE)
00619 return false;
00620 }
00621 }
00622 }
00623
00624 return true;
00625 }
00626
00627
00628 bool Player::_RemoveLines()
00629 {
00630 int blocksInLine = 0;
00631
00632 for (int y = 0; y < playfieldHeight; ++y)
00633 {
00634 for (int x = 0; x < playfieldWidth; ++x)
00635 {
00636 if (gameData.playfield[x][y].pieceId != TETRISPIECE_ID_NONE)
00637 ++blocksInLine;
00638 }
00639
00640 if (blocksInLine == playfieldWidth)
00641 {
00642 _RemoveLine(y);
00643 return true;
00644 }
00645
00646 blocksInLine = 0;
00647 }
00648
00649 return false;
00650 }
00651
00652
00653 void Player::_RemoveLine(int line)
00654 {
00655 TetrisPieceConnectivityInfo *connectivityInfo = NULL;
00656
00657 for (int x = 0; x < playfieldWidth; ++x)
00658 {
00659
00660 connectivityInfo = gameData.playfield[x][line].connectivityInfo;
00661 if (connectivityInfo)
00662 {
00663 connectivityInfo->counter--;
00664
00665 if (connectivityInfo->counter == 0)
00666 {
00667
00668 int slot = GetPowerupQueueSlot();
00669 if (slot >= 0)
00670 {
00671 Powerup *powerup = PowerupUtils::GetStaticInstance(connectivityInfo->powerupId);
00672 QueuePowerup(powerup, slot);
00673 }
00674
00675 gameData.playfield[x][line].Free();
00676 }
00677 }
00678 }
00679
00680 for (int y = line; y > 0; --y)
00681 {
00682 for (int x = 0; x < playfieldWidth; ++x)
00683 {
00684 gameData.playfield[x][y] = gameData.playfield[x][y-1];
00685 }
00686 }
00687
00688 for (int x = 0; x < playfieldWidth; ++x)
00689 {
00690 gameData.playfield[x][0].pieceId = TETRISPIECE_ID_NONE;
00691 gameData.playfield[x][0].SetConnectivityInfo(NULL);
00692 }
00693
00694 gameData.lines++;
00695 gameData.score++;
00696
00697 if (g_options->players == 1)
00698 {
00699 if (gameData.lines % 10 == 0)
00700 _IncreaseLevel();
00701
00702 return;
00703 }
00704
00705 int tmpMaxLines = isHandicapEnabled ? profile.maxLines : g_options->profile.maxLines;
00706
00707 if (tmpMaxLines && gameData.lines == tmpMaxLines)
00708 {
00709 _DisplayWinner(id);
00710 return;
00711 }
00712
00713 int tmpAttackRate = isHandicapEnabled ? profile.attackRate : g_options->profile.attackRate;
00714
00715
00716 if (tmpAttackRate && gameData.score % tmpAttackRate == 0)
00717 {
00718 _IncreaseLevelAllBut(id);
00719 }
00720 }