|
|
|
@ -40,6 +40,7 @@ class CardGameRef : public olc::PixelGameEngine |
|
|
|
|
DRAW, |
|
|
|
|
PICK, |
|
|
|
|
RESULT, |
|
|
|
|
PICKCOLOR, |
|
|
|
|
VICTORY |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -62,14 +63,15 @@ class CardGameRef : public olc::PixelGameEngine |
|
|
|
|
std::vector<Decal*>IMAGES; |
|
|
|
|
Rect cardBorder,cardBack,skip,reverse,wild,drawTwo,drawFour; |
|
|
|
|
Decal*cardTilesheet; |
|
|
|
|
Hand playerHand; |
|
|
|
|
std::vector<Hand>opponentHands; |
|
|
|
|
std::vector<Hand>hands; |
|
|
|
|
CardPile startingPile,drawPile,discardPile; |
|
|
|
|
QuickGUI::Manager playerPickMenu; |
|
|
|
|
QuickGUI::Button *TwoPlayerButton,*ThreePlayerButton,*FourPlayerButton; |
|
|
|
|
|
|
|
|
|
GameState state=AIPICK; |
|
|
|
|
|
|
|
|
|
int playerTurn=0; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
CardGameRef() |
|
|
|
|
{ |
|
|
|
@ -77,24 +79,86 @@ public: |
|
|
|
|
sAppName = "Uno!"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TurnRequiresDraw(){ |
|
|
|
|
Card&topCard=discardPile.back(); |
|
|
|
|
for(Card&card:hands[playerTurn]){ |
|
|
|
|
if(card.col==topCard.col || card.val==topCard.val || card.val==WILD||card.val==DRAWFOUR){ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ReshuffleDrawPile(){ |
|
|
|
|
while(discardPile.size()>1){ |
|
|
|
|
int randomCardIndex=rand()%(discardPile.size()-1); |
|
|
|
|
drawPile.push_back(discardPile[randomCardIndex]); |
|
|
|
|
drawPile.back().faceDown=true; |
|
|
|
|
discardPile.erase(discardPile.begin()+randomCardIndex); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DrawCard(Hand&hand){ |
|
|
|
|
void DrawCard(Hand&hand,bool faceUp=false){ |
|
|
|
|
if(drawPile.size()==0){ |
|
|
|
|
ReshuffleDrawPile(); |
|
|
|
|
} |
|
|
|
|
if(drawPile.size()>0){//It's possible all the cards in the game may have been drawn,
|
|
|
|
|
hand.push_back(drawPile.back()); |
|
|
|
|
hand.back().faceDown=!faceUp; |
|
|
|
|
drawPile.erase(drawPile.end()-1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DisplayCardPile(vf2d pos,CardPile&pile){ |
|
|
|
|
if(pile.size()>0){ |
|
|
|
|
for(int i=0;i<pile.size()/10+1;i++){ |
|
|
|
|
DrawRotatedDecal(pos+vf2d{float(i),-float(i)}/2,GetCardImage(Color::RED,CardValue::ZERO,true),0,{24,32}); |
|
|
|
|
} |
|
|
|
|
DrawRotatedDecal(pos+vf2d{float(pile.size()/10),-float(pile.size()/10)}/2,GetCardImage(pile.back().col,pile.back().val,pile.back().faceDown),0,{24,32}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float degToRad(float deg){ |
|
|
|
|
return deg*(PI/180); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void DrawGameBoard(){ |
|
|
|
|
DisplayCardPile({100,88},drawPile); |
|
|
|
|
DisplayCardPile({156,88},discardPile); |
|
|
|
|
|
|
|
|
|
vf2d playerHandCenter = {128,220}; |
|
|
|
|
Hand&playerHand=hands[0]; |
|
|
|
|
float spreadAngle=15; |
|
|
|
|
float currentAngle=-90; |
|
|
|
|
float cardDistance=64; |
|
|
|
|
if(playerHand.size()>8){ //Handle a case where the hand size is really large. We max out at 120 degrees.
|
|
|
|
|
currentAngle=-int(playerHand.size())/2*120/playerHand.size()-90; |
|
|
|
|
} else { //Small hand size, we can slowly fan out further.
|
|
|
|
|
currentAngle=-int(playerHand.size())/2*15-90; |
|
|
|
|
} |
|
|
|
|
auto GetHandLoopCounter = [&](){ |
|
|
|
|
//Because an even amount of cards needs to skip the center but we increment by the same
|
|
|
|
|
//currentAngle value, we will pretend there's an additional card but we'll skip it.
|
|
|
|
|
if(playerHand.size()%2==0){ |
|
|
|
|
return playerHand.size()+1; |
|
|
|
|
} else { |
|
|
|
|
return playerHand.size(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
for(int i=0;i<GetHandLoopCounter();i++){ |
|
|
|
|
if(playerHand.size()%2==0&&playerHand.size()/2==i){ |
|
|
|
|
continue; //The middle section will be dropped if we have an even number of cards.
|
|
|
|
|
} |
|
|
|
|
Card¤tCard=playerHand[i]; |
|
|
|
|
DrawRotatedDecal(playerHandCenter+vf2d{cos(degToRad(currentAngle)),sin(degToRad(currentAngle))}*cardDistance,GetCardImage(currentCard.col,currentCard.val,currentCard.faceDown),degToRad(currentAngle+90),{24,32},{0.6,0.6}); |
|
|
|
|
if(playerHand.size()>8){ |
|
|
|
|
currentAngle+=120/playerHand.size(); |
|
|
|
|
}else{ |
|
|
|
|
currentAngle+=15; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GenerateCards(){ |
|
|
|
|
for(int color=0;color<4;color++){ |
|
|
|
|
for(int numb=0;numb<13;numb++){ |
|
|
|
@ -233,12 +297,16 @@ public: |
|
|
|
|
startingPile.erase(startingPile.begin()+randomCardIndex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DrawCard(discardPile,true); |
|
|
|
|
|
|
|
|
|
TwoPlayerButton=new QuickGUI::Button(playerPickMenu,"1 Opponent",{128-42,20},{84,40}); |
|
|
|
|
ThreePlayerButton=new QuickGUI::Button(playerPickMenu,"2 Opponents",{128-42,94},{84,40}); |
|
|
|
|
FourPlayerButton=new QuickGUI::Button(playerPickMenu,"3 Opponents",{128-42,168},{84,40}); |
|
|
|
|
|
|
|
|
|
hands.emplace_back(); |
|
|
|
|
|
|
|
|
|
for(int i=0;i<7;i++){ |
|
|
|
|
DrawCard(playerHand); |
|
|
|
|
DrawCard(hands[0],true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
@ -281,12 +349,32 @@ public: |
|
|
|
|
for (int i=0;i<7;i++){ |
|
|
|
|
DrawCard(opponent); |
|
|
|
|
} |
|
|
|
|
opponentHands.push_back(opponent); |
|
|
|
|
hands.push_back(opponent); |
|
|
|
|
} |
|
|
|
|
state=GameState::DRAW; |
|
|
|
|
} |
|
|
|
|
playerPickMenu.DrawDecal(this); |
|
|
|
|
}break; |
|
|
|
|
case DRAW:{ |
|
|
|
|
DrawGameBoard(); |
|
|
|
|
if(!TurnRequiresDraw()){ |
|
|
|
|
state=GameState::PICK; |
|
|
|
|
} |
|
|
|
|
if(playerTurn==0){ |
|
|
|
|
DrawString({0,224},"Player is drawing cards...");
|
|
|
|
|
} else { |
|
|
|
|
DrawString({0,224},"Opponent "+std::to_string(playerTurn)+" is drawing cards..."); |
|
|
|
|
} |
|
|
|
|
}break; |
|
|
|
|
case PICK:{ |
|
|
|
|
DrawGameBoard(); |
|
|
|
|
}break; |
|
|
|
|
case RESULT:{ |
|
|
|
|
DrawGameBoard(); |
|
|
|
|
}break; |
|
|
|
|
case PICKCOLOR:{ |
|
|
|
|
DrawGameBoard(); |
|
|
|
|
}break; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|