Attempt #7?!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Meteos/main.cpp

1061 lines
37 KiB

#include <random>
#include "gameDefines.h"
#include <assert.h>
2 years ago
Meteos*game;
struct BlockMatchingInfo{
int col;
int ind;
int c=-1;
bool changeToLaunched=true;
};
bool Meteos::OnUserCreate()
2 years ago
{
game=this;
2 years ago
SPRITES["blocks_test.png"].Load("assets/blocks_test.png");
std::random_device rd; //Will be used to obtain a seed for the random number engine
gen=std::mt19937(rd()); //Standard mersenne_twister_engine seeded with rd()
randBlockPos=std::uniform_int_distribution<>(0, 9);
coinFlip=std::uniform_int_distribution<>(0, 1);
comboOverlayOffset=std::uniform_int_distribution<>(-16,16);
gameBoard=Board({10,14},0.02f,0.04f,1.2f,0.04f,0.4f,{-1.f,-1.5f,-2.f,-2.5f,-4.f},1.7f,2.0f,0.2f,{3,3,1,2,3,0,0,0,0,0},
60*10,SPRITES["blocks_test.png"]);
return true;
}
2 years ago
bool Meteos::OnUserUpdate(float fElapsedTime)
{
if (gameCanRun){
accumulatedTime+=fElapsedTime;
if (accumulatedTime>=1/60.0f) {
updateGame(1/60.0f);
frameTime++;
accumulatedTime=0;
}
handleInput();
}
drawGame(fElapsedTime,!gameCanRun);
return true;
}
void Meteos::handleInput(){
if (GetMouse(0).bHeld){
int mouseX=(GetMouseX()-gameBoard.drawOffset.x);
int mouseY=(GetMouseY()-gameBoard.drawOffset.y);
int mouseCol=mouseX/12;
int mouseRow=mouseY/12;
if (mouseCol>=0&&mouseCol<gameBoard.boardSize.x) {
for (int y=0;y<gameBoard.getBlocks(mouseCol).size();y++){
Block&b=gameBoard.getBlocks(mouseCol)[y];
if (b.pos.y/12==mouseRow){
SelectedBlockData newData={mouseCol,y,-1};
if (gameBoard.selectedBlock.col!=-1&&mouseCol==gameBoard.selectedBlock.col&&newData.col==mouseCol){
//See if these two can be swapped.
Block&b1=gameBoard.getBlock(gameBoard.selectedBlock);
Block&b2=gameBoard.getBlock(newData);
int y1=(gameBoard.selectedBlock.c!=-1)?gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlockPosition(gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks()[gameBoard.selectedBlock.ind]).y:gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y;
int y2=(newData.c!=-1)?gameBoard.getBlockClumps()[newData.c].getBlockPosition(gameBoard.getBlockClumps()[newData.c].getBlocks()[newData.ind]).y:gameBoard.getBlocks(newData.col)[newData.ind].pos.y;
if (b1.pos.x==b2.pos.x&&std::abs(y1-y2)<=12&&&b1!=&b2){
//Swap the two!
BlockColor tempCol=b1.col;
b1.col=b2.col;
b2.col=tempCol;
}
}
gameBoard.selectedBlock=newData;
goto found;
}
}
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
if (b.pos.x/12==mouseCol&&c.getBlockPosition(b).y<=mouseY&&c.getBlockPosition(b).y+12>mouseY){
SelectedBlockData newData={mouseCol,j,i};
if (gameBoard.selectedBlock.col!=-1&&mouseCol==gameBoard.selectedBlock.col){
//See if these two can be swapped.
Block&b1=gameBoard.getBlock(gameBoard.selectedBlock);
Block&b2=gameBoard.getBlock(newData);
int y1=(gameBoard.selectedBlock.c!=-1)?gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlockPosition(gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks()[gameBoard.selectedBlock.ind]).y:gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y;
int y2=(newData.c!=-1)?gameBoard.getBlockClumps()[newData.c].getBlockPosition(gameBoard.getBlockClumps()[newData.c].getBlocks()[newData.ind]).y:gameBoard.getBlocks(newData.col)[newData.ind].pos.y;
if (b1.pos.x==b2.pos.x&&std::abs(y1-y2)<=12&&&b1!=&b2){
//Swap the two!
BlockColor tempCol=b1.col;
b1.col=b2.col;
b2.col=tempCol;
}
}
gameBoard.selectedBlock=newData;
goto found;
}
}
}
}
found:
if (gameBoard.selectedBlock.c==-1&&gameBoard.selectedBlock.col!=-1&&mouseRow<gameBoard.boardSize.y&&gameBoard.selectedBlock.ind==gameBoard.getBlocks(gameBoard.selectedBlock.col).size()-1&&gameBoard.boardSize.y-mouseRow>gameBoard.getBlocks(gameBoard.selectedBlock.col).size()&&gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y>12){
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
if (b.pos.x/12==gameBoard.selectedBlock.col&&gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y-b.pos.y<=12){
goto notAllowed;
}
}
}
//Fling the block upwards.
BlockClump newClump;
Block&targetBlock=gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind];
newClump.y=targetBlock.pos.y-1;
newClump.launchTime=999999;
newClump.vspeed=gameBoard.launchSpd[0];
newClump.flinged=true;
newClump.addBlock(gameBoard.selectedBlock.col,targetBlock.col);
gameBoard.addClump(newClump);
gameBoard.removeBlock(gameBoard.selectedBlock.col,gameBoard.selectedBlock.ind);
gameBoard.selectedBlock={-1,-1,-1};
}
notAllowed:;
}
if (GetMouse(0).bReleased){
gameBoard.selectedBlock={-1,-1,-1};
}
}
void Meteos::spawnBlocks(float fElapsedTime){
lastBlockSpawn+=fElapsedTime;
if (lastBlockSpawn>=gameBoard.spawnRate){
lastBlockSpawn-=gameBoard.spawnRate;
gameBoard.spawnBlock(randBlockPos(gen));
}
}
void Meteos::handleBlockGravity(float fElapsedTime){
for (int i=gameBoard.getBlockClumps().size()-1;i>=0;i--){
BlockClump&c=gameBoard.getBlockClumps()[i];
if (c.launchTime>0) {
c.launchTime-=fElapsedTime;
} else
if (c.combo>0) {
c.vspeed+=gameBoard.comboGravity;
if (c.vspeed>gameBoard.comboMaxGravity){
c.vspeed=gameBoard.comboMaxGravity;
}
} else {
c.vspeed+=gameBoard.gravity;
if (c.vspeed>gameBoard.maxGravity){
c.vspeed=gameBoard.maxGravity;
}
}
if (c.flinged&&c.y<12*3){
c.flinged=false;
c.launchTime=0;
}
for (int j=gameBoard.getBlockClumps().size()-1;j>=0;j--) {
if (i==j) continue;
BlockClump&c2=gameBoard.getBlockClumps()[j];
for (int k=c2.getBlocks().size()-1;k>=0;k--) {
Block&b2=c2.getBlocks()[k];
for (int l=c.getBlocks().size()-1;l>=0;l--) {
Block&b3=c.getBlocks()[l];
if (c2.getBlockPosition(b2).x==c.getBlockPosition(b3).x&&
c2.getBlockPosition(b2).y+12>=c.getBlockPosition(b3).y&&
c2.getBlockPosition(b2).y<=c.getBlockPosition(b3).y+12) {
c.y=(int)c.y;
c2.y=(int)c2.y;
if (c2.getBlockPosition(b2).y>c.getBlockPosition(b3).y) {
c.y-=12-(c2.getBlockPosition(b2).y-c.getBlockPosition(b3).y);
c.y-=fmod(c.y-c2.y,12);
if (fmod(c2.y-c.y,12)!=0){
std::cout<<"Difference is not divisible by 12!! Value:"<<fmod(c2.y-c.y,12)<<","<<c2.y<<"//"<<c.y<<std::endl;
assert(false);
}
} else {
c2.y-=12-(c.getBlockPosition(b3).y-c2.getBlockPosition(b2).y);
c2.y-=fmod(c.y-c2.y,12);
if (fmod(c.y-c2.y,12)!=0){
std::cout<<"Difference is not divisible by 12!! Value:"<<fmod(c.y-c2.y,12)<<","<<c.y<<"//"<<c2.y<<std::endl;
assert(false);
}
}
float influence=(float)c.getBlocks().size()/(c.getBlocks().size()+c2.getBlocks().size());
int blockCount=c.getBlocks().size();
int blockCount2=c2.getBlocks().size();
//Copy every block from one clump to the other
for (int m=0;m<c2.getBlocks().size();m++) {
Block&b4=c2.getBlocks()[m];
bool exists=false;
for (int n=0;n<c.getBlocks().size();n++){
if ((c.getBlocks()[n].pos.x)/12==(b4.pos.x)/12&&(c.getBlocks()[n].pos.y)/12==(c2.getBlockPosition(b4).y-c.y)/12){
std::cout<<"WARNING! Block overlapping detected at "<<c.getBlocks()[n].pos<<"!"<<std::endl;
exists=true;
blockCount--;
break;
}
}
if (!exists){
c.addBlock(b4.pos.x/12,(c2.getBlockPosition(b4).y-c.y)/12,b4.col);
}
}
if (blockCount+blockCount2!=c.getBlocks().size()) {
std::cout<<"Block size is: "<<c.getBlocks().size()<<" but expected "<<blockCount+blockCount2<<std::endl;
assert(false);
}
bool overlappingBlocks=false;
for (int m=0;m<c.getBlocks().size();m++){
for (int n=0;n<c.getBlocks().size();n++){
if(m==n)continue;
if (c.getBlocks()[m].pos==c.getBlocks()[n].pos){
std::cout<<"Block overlapping detected at "<<c.getBlocks()[m].pos<<"!"<<std::endl;
overlappingBlocks=true;
}
}
}
if (overlappingBlocks){
gameCanRun=false;
return;
}
if (overlappingBlocks){
std::cout<<"Block b3 "<<b3.pos<<"!"<<std::endl;
}
if (!c.flinged&&!c2.flinged){
c.vspeed=std::min(c.vspeed,c2.vspeed);
}
if (c.flinged||c2.flinged){
c.launchTime=0;
}
c.flinged=false;
c2.flinged=false;
c.combo=std::max(c.combo,c2.combo);
c.landTime=std::max(c.landTime,c2.landTime);
c.sortBlocks();
if (i>=j){
i--;
}
gameBoard.removeClump(j);
goto nextClumpCollisionCheck;
}
}
}
}
nextClumpCollisionCheck:;
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
int col=b.pos.x/12;
for (int k=0;k<gameBoard.getBlocks(col).size();k++){
Block&b2=gameBoard.getBlocks(col)[k];
if (c.getBlockPosition(b).y+12>=b2.pos.y&&c.getBlockPosition(b).y<=b2.pos.y+12){
c.y-=c.getBlockPosition(b).y+12-b2.pos.y;
c.vspeed=0;
if (c.landTime>=gameBoard.landTime) {
gameBoard.convertClump(i);
} else {
c.landTime+=fElapsedTime;
}
goto nextClump;
}
}
if (c.getBlockPosition(b).y>=gameBoard.yBottom) {
c.y-=c.getBlockPosition(b).y-gameBoard.yBottom;
c.vspeed=0;
if (c.landTime>=gameBoard.landTime) {
gameBoard.convertClump(i);
} else {
c.landTime+=fElapsedTime;
}
goto nextClump;
}
}
c.landTime=0;
nextClump:;
}
}
void Meteos::matchFlyingBlockClumps(){
for (int g=0;g<gameBoard.getBlockClumps().size();g++){
BlockClump&c=gameBoard.getBlockClumps()[g];
std::vector<BlockMatchingInfo>matchedBlockIDs;
for (Block&b:c.getBlocks()) {
b.addedToLaunchList=false;
}
for (int i=0;i<c.getBlocks().size();i++) {
Block&b=c.getBlocks()[i];
std::vector<BlockMatchingInfo>tempMatchIDsX;
std::vector<BlockMatchingInfo>tempMatchIDsY;
float targetX=b.pos.x;
float targetY=b.pos.y;
bool found=false;
tempMatchIDsX.push_back({(int)b.pos.x/12,i,g});
tempMatchIDsY.push_back({(int)b.pos.x/12,i,g});
rightCheck:
float checkX=targetX+12;
float checkY=targetY;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkX+=12;
tempMatchIDsX.push_back({(int)b.pos.x/12,j,g});
goto outerRightCheck;
}
}
if (c.landTime>0){
for (int h=0;h<gameBoard.getBlockClumps().size();h++){
if (g==h)continue;
BlockClump&c2=gameBoard.getBlockClumps()[h];
if (c2.landTime>0){
for (int j=0;j<c2.getBlocks().size();j++){
Block&b2=c2.getBlocks()[j];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&c2.getBlockPosition(b2).y-c.y==checkY) {
found=true;
checkX+=12;
tempMatchIDsX.push_back({(int)b2.pos.x/12,j,h});
goto outerRightCheck;
}
}
}
}
}
outerRightCheck:;
}while(found);
leftCheck:
checkX=targetX-12;
checkY=targetY;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkX-=12;
tempMatchIDsX.push_back({(int)b.pos.x/12,j,g});
goto outerLeftCheck;
}
}
if (c.landTime>0){
for (int h=0;h<gameBoard.getBlockClumps().size();h++){
if (g==h)continue;
BlockClump&c2=gameBoard.getBlockClumps()[h];
if (c2.landTime>0){
for (int j=0;j<c2.getBlocks().size();j++){
Block&b2=c2.getBlocks()[j];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&c2.getBlockPosition(b2).y-c.y==checkY) {
found=true;
checkX-=12;
tempMatchIDsX.push_back({(int)b2.pos.x/12,j,h});
goto outerLeftCheck;
}
}
}
}
}
outerLeftCheck:;
}while(found);
upCheck:
checkX=targetX;
checkY=targetY-12;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY-=12;
tempMatchIDsY.push_back({(int)b.pos.x/12,j,g});
goto outerUpCheck;
}
}
if (c.landTime>0){
for (int h=0;h<gameBoard.getBlockClumps().size();h++){
if (g==h)continue;
BlockClump&c2=gameBoard.getBlockClumps()[h];
if (c2.landTime>0){
for (int j=0;j<c2.getBlocks().size();j++){
Block&b2=c2.getBlocks()[j];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&c2.getBlockPosition(b2).y-c.y==checkY) {
found=true;
checkY-=12;
tempMatchIDsY.push_back({(int)b2.pos.x/12,j,h});
goto outerUpCheck;
}
}
}
}
}
outerUpCheck:;
}while(found);
downCheck:
checkX=targetX;
checkY=targetY+12;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY+=12;
tempMatchIDsY.push_back({(int)b.pos.x/12,j,g});
goto outerDownCheck;
}
}
if (c.landTime>0){
for (int h=0;h<gameBoard.getBlockClumps().size();h++){
if (g==h)continue;
BlockClump&c2=gameBoard.getBlockClumps()[h];
if (c2.landTime>0){
for (int j=0;j<c2.getBlocks().size();j++){
Block&b2=c2.getBlocks()[j];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&c2.getBlockPosition(b2).y-c.y==checkY) {
found=true;
checkY+=12;
tempMatchIDsY.push_back({(int)b2.pos.x/12,j,h});
goto outerDownCheck;
}
}
}
}
}
outerDownCheck:;
}while(found);
if (tempMatchIDsX.size()>2||tempMatchIDsY.size()>2) {
if (tempMatchIDsX.size()>2) {
for (BlockMatchingInfo i:tempMatchIDsX) {
if (i.c!=g){
for (int j=0;j<gameBoard.getBlockClumps()[i.c].getBlocks().size();j++){
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[j];
if (!bb.addedToLaunchList&&j!=i.ind) {
for (int k=0;k<tempMatchIDsX.size();k++){
if (tempMatchIDsX[k].c==i.c&&tempMatchIDsX[k].ind==j){
goto skipX;
}
}
bb.addedToLaunchList=true;
matchedBlockIDs.push_back({(int)bb.pos.x/12,j,i.c,false});
skipX:;
}
}
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
} else {
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
if (!bb.addedToLaunchList) {
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
}
}
}
if (tempMatchIDsY.size()>2) {
for (BlockMatchingInfo i:tempMatchIDsY) {
if (i.c!=g){
for (int j=0;j<gameBoard.getBlockClumps()[i.c].getBlocks().size();j++){
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[j];
if (!bb.addedToLaunchList&&j!=i.ind) {
for (int k=0;k<tempMatchIDsY.size();k++){
if (tempMatchIDsY[k].c==i.c&&tempMatchIDsY[k].ind==j){
goto skipY;
}
}
bb.addedToLaunchList=true;
matchedBlockIDs.push_back({(int)bb.pos.x/12,j,i.c,false});
skipY:;
}
}
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
} else {
Block&bb=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
if (!bb.addedToLaunchList) {
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
}
}
}
}
}
for (BlockMatchingInfo i:matchedBlockIDs) {
if (g==i.c){
Block&b=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
b.col=BlockColor::LAUNCHED;
} else {
Block&b=gameBoard.getBlockClumps()[i.c].getBlocks()[i.ind];
if (!b.markedForRemoval){
if (i.changeToLaunched){
b.col=BlockColor::LAUNCHED;
c.addBlock(i.col,(gameBoard.getBlockClumps()[i.c].getBlockPosition(b).y-c.y)/12,BlockColor::LAUNCHED);
} else {
c.addBlock(i.col,(gameBoard.getBlockClumps()[i.c].getBlockPosition(b).y-c.y)/12,b.col);
}
}
if (i.changeToLaunched){
b.col=BlockColor::LAUNCHED;
}
b.markedForRemoval=true;
}
}
if (matchedBlockIDs.size()>0){
c.vspeed=gameBoard.launchSpd[std::min(c.combo,(int)gameBoard.launchSpd.size()-1)]/(1+(c.getBlocks().size()*gameBoard.blockWeight));
c.launchTime=gameBoard.launchTime;
c.combo++;
score+=MATCH_SCORE*c.combo;
displayTargetScore+=MATCH_SCORE*c.combo;
vi2d randomOffset={comboOverlayOffset(gen),comboOverlayOffset(gen)};
comboDisplayList.push_back({c.getBlockPosition(gameBoard.getBlockClumps()[matchedBlockIDs[0].c].getBlocks()[matchedBlockIDs[0].ind])+randomOffset,c.combo});
//std::cout<<"Combo value is "<<c.combo<<std::endl;
}
}
}
void Meteos::cleanupBlockClumps(){
for (int g=0;g<gameBoard.getBlockClumps().size();g++){
BlockClump&c=gameBoard.getBlockClumps()[g];
for (int i=0;i<c.getBlocks().size();i++){
Block&b=c.getBlocks()[i];
if (b.markedForRemoval){
c.removeBlock(i--);
}
}
}
}
void Meteos::matchGroundedBlocks(){
std::vector<BlockMatchingInfo>matchedBlockIDs; //Col followed by index
for (int i=0;i<gameBoard.boardSize.x;i++){
for (Block&b:gameBoard.getBlocks(i)) {
b.addedToLaunchList=false;
}
for (int j=0;j<gameBoard.getBlocks(i).size();j++) {
Block&b=gameBoard.getBlocks(i)[j];
std::vector<BlockMatchingInfo>tempMatchIDsX; //Col followed by index
std::vector<BlockMatchingInfo>tempMatchIDsY; //Col followed by index
float targetX=b.pos.x;
float targetY=b.pos.y;
bool found=false;
tempMatchIDsX.push_back({i,j});
tempMatchIDsY.push_back({i,j});
rightBoardCheck:
float checkX=1;
float checkY=targetY;
do{
found=false;
if (i+checkX<gameBoard.boardSize.x) {
for (int k=0;k<gameBoard.getBlocks(i+checkX).size();k++){
Block&b2=gameBoard.getBlocks(i+checkX)[k];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&std::abs(b2.pos.y-checkY)<0.2) {
found=true;
tempMatchIDsX.push_back({(int)(i+checkX),k});
checkX++;
goto outercheck2;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&std::abs(c.getBlockPosition(b2).y-checkY)<0.2){
found=true;
tempMatchIDsX.push_back({(int)(b2.pos.x/12),l,k});
checkX++;
goto outercheck2;
}
}
}
}
outercheck2:;
}
}while(found);
leftBoardCheck:
checkX=-1;
checkY=targetY;
do{
found=false;
if (i+checkX>=0) {
for (int k=0;k<gameBoard.getBlocks(i+checkX).size();k++){
Block&b2=gameBoard.getBlocks(i+checkX)[k];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&std::abs(b2.pos.y-checkY)<0.2) {
found=true;
tempMatchIDsX.push_back({(int)(i+checkX),k});
checkX--;
goto outercheck3;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&std::abs(c.getBlockPosition(b2).y-checkY)<0.2){
found=true;
tempMatchIDsX.push_back({(int)(b2.pos.x/12),l,k});
checkX--;
goto outercheck3;
}
}
}
}
outercheck3:;
}
}while(found);
upBoardCheck:
checkX=targetX;
checkY=targetY-12;
do{
found=false;
for (int k=0;k<gameBoard.getBlocks(i).size();k++){
Block&b2=gameBoard.getBlocks(i)[k];
if (j==k)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&std::abs(b2.pos.y-checkY)<0.2) {
found=true;
checkY-=12;
tempMatchIDsY.push_back({i,k});
goto outercheck4;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&c.getBlockPosition(b2).x==checkX&&std::abs(c.getBlockPosition(b2).y-checkY)<0.2){
found=true;
checkY-=12;
tempMatchIDsY.push_back({(int)(b2.pos.x/12),l,k});
goto outercheck4;
}
}
}
}
outercheck4:;
}while(found);
downBoardCheck:
checkX=targetX;
checkY=targetY+12;
do{
found=false;
for (int k=0;k<gameBoard.getBlocks(i).size();k++){
Block&b2=gameBoard.getBlocks(i)[k];
if (j==k)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&std::abs(b2.pos.y-checkY)<0.2) {
found=true;
checkY+=12;
tempMatchIDsY.push_back({i,k});
goto outercheck1;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&c.getBlockPosition(b2).x==checkX&&std::abs(c.getBlockPosition(b2).y-checkY)<0.2){
found=true;
checkY+=12;
tempMatchIDsY.push_back({(int)(b2.pos.x/12),l,k});
goto outercheck1;
}
}
}
}
outercheck1:;
}while(found);
if (tempMatchIDsX.size()>2||tempMatchIDsY.size()>2) {
if (tempMatchIDsX.size()>2) {
for (BlockMatchingInfo&info:tempMatchIDsX) {
if (info.c!=-1) {
BlockClump&c=gameBoard.getBlockClumps()[info.c];
Block&bb=c.getBlocks()[info.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(info);
}
} else {
Block&bb=gameBoard.getBlocks(info.col)[info.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(info);
}
}
}
}
if (tempMatchIDsY.size()>2) {
for (BlockMatchingInfo&info:tempMatchIDsY) {
if (info.c!=-1) {
BlockClump&c=gameBoard.getBlockClumps()[info.c];
Block&bb=c.getBlocks()[info.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(info);
}
} else {
Block&bb=gameBoard.getBlocks(info.col)[info.ind];
if (!bb.addedToLaunchList){
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(info);
}
}
}
}
}
}
}
if (matchedBlockIDs.size()>0) {
BlockClump c;
bool firstBlock=true;
vf2d baseBlockPos;
for (BlockMatchingInfo&info:matchedBlockIDs) {
if (info.c!=-1){
Block&b=gameBoard.getBlockClumps()[info.c].getBlocks()[info.ind];
if (firstBlock) {
baseBlockPos=gameBoard.getBlockClumps()[info.c].getBlockPosition(b);
c.y=baseBlockPos.y-1;
firstBlock=false;
}
b.col=BlockColor::LAUNCHED;
} else {
Block&b=gameBoard.getBlocks(info.col)[info.ind];
if (firstBlock) {
baseBlockPos=b.pos;
c.y=baseBlockPos.y-1;
firstBlock=false;
}
b.col=BlockColor::LAUNCHED;
}
}
for (BlockMatchingInfo&info:matchedBlockIDs) {
if (info.c!=-1){
if (gameBoard.getBlockClumps()[info.c].getBlocks().size()>0){
if (c.combo<gameBoard.getBlockClumps()[info.c].combo){
c.combo=gameBoard.getBlockClumps()[info.c].combo;
}
for (int i=gameBoard.getBlockClumps()[info.c].getBlocks().size()-1;i>=0;i--) {
Block&b2=gameBoard.getBlockClumps()[info.c].getBlocks()[i];
if ((int)fmod(std::abs(std::round(gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y)-std::round(baseBlockPos.y)),12)!=0){
std::cout<<"Difference is not equal to 0! Value:"<<(int)fmod(std::abs(std::round(gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y)-std::round(baseBlockPos.y)),12)<<" "<<gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y<<"//"<<baseBlockPos.y<<std::endl;
assert(false);
}
c.addBlock(b2.pos.x/12,((int)gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y-(int)baseBlockPos.y)/12,b2.col);
//std::cout<<"Added block @"<<b2.pos.x/12<<((int)gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y-(int)baseBlockPos.y)/12<<std::endl;
gameBoard.getBlockClumps()[info.c].removeBlock(i);
}
}
} else {
Block&b=gameBoard.getBlocks(info.col)[info.ind];
int yPos=b.pos.y;
for (int i=gameBoard.getBlocks(info.col).size()-1;i>=0;i--){
Block&b2=gameBoard.getBlocks(info.col)[i];
if (b2.pos.y<=yPos){
if ((int)fmod((int)b2.pos.y-(int)baseBlockPos.y,12)!=0){
std::cout<<"Difference is not equal to 0! Value:"<<(int)fmod((int)b2.pos.y-(int)baseBlockPos.y,12)<<" "<<b2.pos.y<<"//"<<baseBlockPos.y<<std::endl;
assert(false);
}
c.addBlock(info.col,((int)b2.pos.y-(int)baseBlockPos.y)/12,b2.col);
//std::cout<<"Added block @"<<info.col<<((int)b2.pos.y-(int)baseBlockPos.y)/12<<std::endl;
//b2.markedForRemoval=true;
gameBoard.removeBlock(info.col,i);
}
}
}
}
gameBoard.addClump(c);
gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].vspeed=gameBoard.launchSpd[std::min(gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo,(int)gameBoard.launchSpd.size()-1)]/(1+(gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].getBlocks().size()*gameBoard.blockWeight));
gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].launchTime=gameBoard.launchTime;
gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo++;
score+=MATCH_SCORE*gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo;
displayTargetScore+=MATCH_SCORE*gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo;
vi2d randomOffset={comboOverlayOffset(gen),comboOverlayOffset(gen)};
comboDisplayList.push_back({baseBlockPos+randomOffset,gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo});
//std::cout<<"Combo value is "<<gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].combo<<std::endl;
}
}
void Meteos::matchBlocks(){
matchFlyingBlockClumps();
cleanupBlockClumps();
matchGroundedBlocks();
}
void Meteos::cleanupBlocks(){
for (int i=gameBoard.getBlockClumps().size()-1;i>=0;i--){ //Resolve BlockClump movements.
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=c.getBlocks().size()-1;j>=0;j--){
Block&b=c.getBlocks()[j];
b.addedToLaunchList=false;
if (c.vspeed<0&&c.getBlockPosition(b).y<0||b.markedForRemoval){
if (c.vspeed<0&&c.getBlockPosition(b).y<0){
accumulatedScore+=BASE_SCORE*c.combo;
score+=BASE_SCORE*c.combo;
blocksInAttackQueue++;
lastBlockLaunched=0.0f;
if (blocksInAttackQueue%10==0){
accumulatedScore+=BONUS_ATTACK_SCORE;
score+=BONUS_ATTACK_SCORE;
}
}
//std::cout<<"Removed block @"<<b.pos<<" from clump "<<i<<std::endl;
c.removeBlock(j);
}
}
c.y+=c.vspeed;
if (c.getBlocks().size()<=0) {
//std::cout<<"Block Clump "<<i<<" is empty. Removing."<<std::endl;
gameBoard.removeClump(i);
continue;
}
}
}
void Meteos::handleWarningLevels(float fElapsedTime){
bool noWarning=true;
for (int i=0;i<gameBoard.boardSize.x;i++){
if (gameBoard.getBlocks(i).size()>=gameBoard.boardSize.y){
gameBoard.warningFlashingLevel[i]+=fElapsedTime;
gameBoard.warningLevel++;
noWarning=false;
} else {
gameBoard.warningFlashingLevel[i]=0;
}
for (int y=gameBoard.getBlocks(i).size()-1;y>=0;y--){
Block&b=gameBoard.getBlocks(i)[y];
b.addedToLaunchList=false;
if (b.markedForRemoval){
gameBoard.removeBlock(i,y);
continue;
}
}
}
if (noWarning){
gameBoard.warningLevel=0;
} else
if (gameBoard.warningLevel>=gameBoard.maxWarningLevel){
//Planet crashes! For now we just clear all blocks and clumps on the board.
while (gameBoard.getBlockClumps().size()>0){
gameBoard.removeClump(0);
}
for (int i=0;i<gameBoard.boardSize.x;i++){
while (gameBoard.getBlocks(i).size()>0){
gameBoard.removeBlock(i,0);
}
}
gameBoard.warningLevel=0;
}
}
void Meteos::validateSelectedBlock(){
//Invalidate the selected block if something is strange about it.
if (gameBoard.selectedBlock.col!=-1){
if (gameBoard.selectedBlock.c!=-1){
if (!(gameBoard.selectedBlock.c<gameBoard.getBlockClumps().size()&&gameBoard.selectedBlock.ind<gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks().size()&&gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks()[gameBoard.selectedBlock.ind].pos.x/12==gameBoard.selectedBlock.col)){
gameBoard.selectedBlock={-1};
return;
}
} else {
if (!(gameBoard.selectedBlock.ind<gameBoard.getBlocks(gameBoard.selectedBlock.col).size())){
gameBoard.selectedBlock={-1};
return;
}
}
}
}
void Meteos::handleComboAnimations(){
for (int i=comboDisplayList.size()-1;i>=0;i--){
ComboOverlay&c=comboDisplayList[i];
c.lifetime++;
c.pos.y-=0.1;
if (c.lifetime>60){
comboDisplayList.erase(comboDisplayList.begin()+i);
}
}
}
void Meteos::updateScoreDisplay(float fElapsedTime){
if (blocksInAttackQueue){
lastBlockLaunched+=fElapsedTime;
if (lastBlockLaunched>=blockLaunchWaitPeriod){
blocksInAttackQueue=0;
accumulatedScore=0;
displayTargetScore=score;
}
}
lastScoreDisplayUpdate+=fElapsedTime;
if (lastScoreDisplayUpdate>=SCORE_DISPLAY_UPDATE_RATE){
if (displayScore!=displayTargetScore){
int tempScore=displayTargetScore;
int tempDisplayScore=displayScore;
std::vector<int>targetScoreDigits;
std::vector<int>displayScoreDigits;
while (tempScore>0){
int digit=tempScore%10;
tempScore/=10;
targetScoreDigits.insert(targetScoreDigits.begin(),digit);
}
while (tempDisplayScore>0){
int digit=tempDisplayScore%10;
tempDisplayScore/=10;
displayScoreDigits.insert(displayScoreDigits.begin(),digit);
}
//std::cout<<std::endl;
int marker=0;
while (marker<targetScoreDigits.size()||marker<displayScoreDigits.size()){
int targetScoreDigit=marker<targetScoreDigits.size()?targetScoreDigits[targetScoreDigits.size()-1-marker]:0;
int displayScoreDigit=marker<displayScoreDigits.size()?displayScoreDigits[displayScoreDigits.size()-1-marker]:0;
if (displayScoreDigit!=targetScoreDigit){
if (displayScoreDigit+1<10){
displayScore+=std::pow(10,marker);
} else {
displayScore-=std::pow(10,marker)*9;
}
}
marker++;
}
}
lastScoreDisplayUpdate=0;
}
}
void Meteos::updateGame(float fElapsedTime){
spawnBlocks(fElapsedTime);
handleBlockGravity(fElapsedTime);
matchBlocks();
cleanupBlocks();
handleWarningLevels(fElapsedTime);
validateSelectedBlock();
handleComboAnimations();
updateScoreDisplay(fElapsedTime);
for (Star s:starField){
s.Update();
}
}
void Meteos::drawGame(float fElapsedTime,bool debugView){
Clear(VERY_DARK_BLUE);
for (Star s:starField){
s.Draw();
}
for (int x=-1;x<=gameBoard.boardSize.x;x++){
for (int y=0;y<=gameBoard.boardSize.y;y++){
if (x==-1||x==10||y==14){
FillRectDecal({(float)(gameBoard.drawOffset.x+x*12),(float)(gameBoard.drawOffset.y+y*12)},{12,12},Pixel(0,0,0,255));
} else {
DrawRectDecal({(float)(gameBoard.drawOffset.x+x*12),(float)(gameBoard.drawOffset.y+y*12)},{12,12},Pixel(255,255,255,64));
}
}
}
int alpha=(debugView)?32:255;
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
DrawPartialDecal(c.getBlockPosition(b)+gameBoard.drawOffset,gameBoard.tileset,{(float)(int)b.col*12,0},{12,12},{1,1},gameBoard.selectedBlock.col!=-1&&gameBoard.selectedBlock.ind==j&&gameBoard.selectedBlock.c==i?Pixel(GREY.r,GREY.g,GREY.b,alpha):Pixel(WHITE.r,WHITE.g,WHITE.b,alpha));
}
//DrawStringDecal({32,c.y+i%4*4},std::to_string(c.landTime),WHITE,{0.4,0.4}); //Draws land times per clump.
}
for (int i=0;i<gameBoard.boardSize.x;i++){
for (int y=0;y<gameBoard.getBlocks(i).size();y++){
Block&b=gameBoard.getBlocks(i)[y];
DrawPartialDecal(b.pos+gameBoard.drawOffset,gameBoard.tileset,{(float)(int)b.col*12,0},{12,12},{1,1},gameBoard.selectedBlock.col!=-1&&gameBoard.selectedBlock.c==-1&&gameBoard.selectedBlock.col==i&&gameBoard.selectedBlock.ind==y?Pixel(GREY.r,GREY.g,GREY.b,alpha):Pixel(WHITE.r,WHITE.g,WHITE.b,alpha));
}
if (gameBoard.warningFlashingLevel[i]>0){
FillRectDecal({gameBoard.drawOffset.x+i*12,gameBoard.drawOffset.y},{12,(float)gameBoard.boardSize.y*12},Pixel(255,64,64,std::abs(sin(gameBoard.warningFlashingLevel[i]*M_PI))*128));
}
2 years ago
}
for (int i=0;i<comboDisplayList.size();i++){
ComboOverlay&c=comboDisplayList[i];
vi2d shadowOffset={1,1};
DrawStringPropDecal(c.pos+gameBoard.drawOffset+shadowOffset,"x"+std::to_string(c.combo),BLACK,{0.8,0.6});
DrawStringPropDecal(c.pos+gameBoard.drawOffset,"x"+std::to_string(c.combo),(c.lifetime%6>=3)?Pixel{207,103,0}:Pixel{255,255,255,180},{0.8,0.6});
}
DrawStringDecal(gameBoard.drawOffset+vi2d{-8,-24}+vi2d{1,1},std::to_string(displayScore),BLACK,{2,2});
DrawStringDecal(gameBoard.drawOffset+vi2d{-8,-24},std::to_string(displayScore),WHITE,{2,2});
if (accumulatedScore>0){
DrawStringDecal(gameBoard.drawOffset+vi2d{0,-8}+vi2d{1,1},"+"+std::to_string(accumulatedScore),BLACK,{0.75,0.75});
DrawStringDecal(gameBoard.drawOffset+vi2d{0,-8},"+"+std::to_string(accumulatedScore),frameTime%5>2?Pixel{224, 184, 148}:WHITE,{0.75,0.75});
GradientFillRectDecal(gameBoard.drawOffset+vi2d{gameBoard.boardSize.x*12+16,0}, {32,32}, BLACK, VERY_DARK_GREEN, VERY_DARK_GREEN, BLACK);
DrawRectDecal(gameBoard.drawOffset+vi2d{gameBoard.boardSize.x*12+16,0}, {32,32}, DARK_YELLOW);
std::string attackQueueDisplay="";
if (blocksInAttackQueue<100){
attackQueueDisplay+='0';
}
if (blocksInAttackQueue<10){
attackQueueDisplay+='0';
}
attackQueueDisplay+=std::to_string(blocksInAttackQueue);
Pixel attackQueueDisplayStringColor={66, 125, 92};
if(blocksInAttackQueue<80){
for (int y=0;y<=blocksInAttackQueue/10;y++){
for (int x=0;x<10;x++){
int amt=y*10+x;
if (blocksInAttackQueue>=amt){
if(blocksInAttackQueue<40){
attackQueueDisplayStringColor={66, 120, 245};
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
} else {
attackQueueDisplayStringColor={66, 245, 164};
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
}
}
}
}
} else
if (blocksInAttackQueue<160){
for (int y=0;y<=blocksInAttackQueue/20;y++){
for (int x=0;x<10;x++){
int amt=y*20+x*2;
if (blocksInAttackQueue>=amt){
if(blocksInAttackQueue<140){
attackQueueDisplayStringColor={237, 128, 107};
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
} else {
attackQueueDisplayStringColor=YELLOW;
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
}
}
}
}
} else {
for (int y=0;y<=blocksInAttackQueue/40;y++){
for (int x=0;x<10;x++){
int amt=y*40+x*4;
if (blocksInAttackQueue>amt){
if(blocksInAttackQueue<320){
attackQueueDisplayStringColor=YELLOW;
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
} else {
attackQueueDisplayStringColor={176, 38, 255};
DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor);
}
}
}
}
}
DrawStringDecal(gameBoard.drawOffset-vf2d{GetTextSize(attackQueueDisplay).x*0.85f/2,0}+vi2d{gameBoard.boardSize.x*12+16+16,3},attackQueueDisplay,attackQueueDisplayStringColor,{0.85,1});
}
}
2 years ago
int main()
{
Meteos instance;
if (instance.Construct(256, 240, 4, 4))
instance.Start();
2 years ago
return 0;
}