package com.mehtank.androminion.ui; import java.util.ArrayList; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.Button; import android.widget.GridView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; import com.mehtank.androminion.R; import com.mehtank.androminion.activities.GameActivity; import com.mehtank.androminion.ui.CardView.CardState; import com.mehtank.androminion.util.Achievements; import com.mehtank.androminion.util.CardGroup; import com.mehtank.androminion.util.HapticFeedback; import com.mehtank.androminion.util.HapticFeedback.AlertType; import com.mehtank.androminion.util.PlayerAdapter; import com.mehtank.androminion.util.PlayerSummary; import com.vdom.comms.Event; import com.vdom.comms.Event.EventObject; import com.vdom.comms.GameStatus; import com.vdom.comms.MyCard; import com.vdom.comms.SelectCardOptions; import com.vdom.comms.SelectCardOptions.PickType; public class GameTable extends LinearLayout implements OnItemClickListener, OnItemLongClickListener { @SuppressWarnings("unused") private static final String TAG = "GameTable"; private final GameActivity top; private PlayerAdapter players = new PlayerAdapter(getContext()); public PlayerAdapter getPlayerAdapter() { return players; } GridView handGV, playedGV, islandGV, villageGV, trashGV; CardGroup hand, played, island, village, trash; View islandColumn, villageColumn, trashColumn; TextView playedHeader; LinearLayout myCards; GridView moneyPileGV, vpPileGV, supplyPileGV, prizePileGV, nonSupplyPileGV; CardGroup moneyPile, vpPile, supplyPile, prizePile, nonSupplyPile; LinearLayout tr; LinearLayout gameOver; ScrollView gameOverScroll; View supply; LinearLayout turnView; View myCardView; private static int[] costs = {}; TextView actionText; LinearLayout deckStatus; TurnView turnStatus; /** * Button that are pressed to confirm or decline an option */ Button select, pass; String indicator; GameScrollerView gameScroller; TextView latestTurn; SelectStringView sv; Achievements achievements; CardAnimator animator; ArrayList<ToggleButton> showCardsButtons = new ArrayList<ToggleButton>(); /** * Information about a selected card: group, position in that group, CardState */ private class CardInfo { public CardState cs; public CardGroup parent; public int pos; public CardInfo(CardState cs, CardGroup parent, int pos) { this.cs = cs; this.parent = parent; this.pos = pos; } } /** * List of cards that were selected */ ArrayList<CardInfo> openedCards = new ArrayList<CardInfo>(); int maxOpened = 0; boolean exactOpened = true; boolean myTurn; boolean finalStatsReported = false; double textScale = GameTableViews.textScale; private HelpView helpView; /** * Initialize the card groups at the top of the screen, where the card piles go */ private void initTable() { moneyPile = new CardGroup(top, true); moneyPileGV = (GridView) findViewById(R.id.moneyPileGV); moneyPileGV.setAdapter(moneyPile); moneyPileGV.setOnItemClickListener(this); moneyPileGV.setOnItemLongClickListener(this); vpPile = new CardGroup(top, true); vpPileGV = (GridView) findViewById(R.id.vpPileGV); vpPileGV.setAdapter(vpPile); vpPileGV.setOnItemClickListener(this); vpPileGV.setOnItemLongClickListener(this); supplyPile = new CardGroup(top, true); supplyPileGV = (GridView) findViewById(R.id.supplyPileGV); supplyPileGV.setAdapter(supplyPile); supplyPileGV.setOnItemClickListener(this); supplyPileGV.setOnItemLongClickListener(this); nonSupplyPile = new CardGroup(top, true); nonSupplyPileGV = (GridView) findViewById(R.id.nonSupplyPileGV); nonSupplyPileGV.setAdapter(nonSupplyPile); nonSupplyPileGV.setOnItemClickListener(this); nonSupplyPileGV.setOnItemLongClickListener(this); prizePile = new CardGroup(top, true); prizePileGV = (GridView) findViewById(R.id.prizePileGV); prizePileGV.setAdapter(prizePile); prizePileGV.setOnItemClickListener(this); prizePileGV.setOnItemLongClickListener(this); } /** * Initialize card groups that belong to the user (hand, played, island, village) */ private void initHand() { hand = new CardGroup(top, false); handGV = (GridView) findViewById(R.id.handGV); handGV.setAdapter(hand); handGV.setOnItemClickListener(this); handGV.setOnItemLongClickListener(this); played = new CardGroup(top, false); playedGV = (GridView) findViewById(R.id.playedGV); playedGV.setAdapter(played); playedGV.setOnItemLongClickListener(this); island = new CardGroup(top, false); islandGV = (GridView) findViewById(R.id.islandGV); islandGV.setAdapter(island); islandGV.setOnItemLongClickListener(this); islandColumn = findViewById(R.id.islandColumn); village = new CardGroup(top, false); villageGV = (GridView) findViewById(R.id.villageGV); villageGV.setAdapter(village); villageGV.setOnItemLongClickListener(this); villageColumn = findViewById(R.id.villageColumn); trash = new CardGroup(top, false); trashGV = (GridView) findViewById(R.id.trashGV); trashGV.setAdapter(trash); trashGV.setOnItemLongClickListener(this); trashColumn = findViewById(R.id.trashColumn); playedHeader = (TextView) findViewById(R.id.playedHeader); //only for help myCardView = findViewById(R.id.myCardView); } /** * Initialize player information list (right of the screen) */ private void initTurnPanel() { turnView = (LinearLayout) findViewById(R.id.turnView); select = (Button) findViewById(R.id.select); setSelectText(SelectCardOptions.PickType.SELECT); select.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { cardSelected((Button) v); } }); pass = (Button) findViewById(R.id.pass); pass.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { cardSelected((Button) v); } }); deckStatus = (LinearLayout) findViewById(R.id.deckStatus); players.setContainer(deckStatus); deckStatus.setEnabled(true); turnStatus = new TurnView(top); turnStatus.setTextSize(12.0f); //turnView.addView(turnStatus, 2); actionText = (TextView) findViewById(R.id.actionText); players.setTurnStatus(turnStatus); showCardsButtons.clear(); } public GameTable(Context context) { this(context, null); } public GameTable(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GameTable(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); //TODO remove this workaround //super(context, attrs, defStyle); // fails with exception... this.top = (GameActivity) context; setOrientation(VERTICAL); animator = new CardAnimator(); try { achievements = new Achievements(top); } catch(Exception e) { e.printStackTrace(); } LayoutInflater.from(context).inflate(R.layout.view_gametable, this, true); supply = findViewById(R.id.supply); initTable(); tr = (LinearLayout) findViewById(R.id.tr); initHand(); initTurnPanel(); gameOver = (LinearLayout) findViewById(R.id.gameOver); gameOverScroll = (ScrollView) findViewById(R.id.gameOverScroll); gameScroller = (GameScrollerView) findViewById(R.id.gameScroller); gameScroller.setGameEvent("Dominion app loaded!", true, 0); /** * findViewById(R.id.actionText) must be in here so that it gets fadet out whenever everything else fades out. */ helpView = new HelpView(this.top, new View[] {supply, turnView, myCardView, gameScroller, findViewById(R.id.actionText)}, new View[] {tr, supply, supply, tr}); } public void showHelp(int page) { try { top.addView(helpView); } catch (IllegalStateException e) {} helpView.showHelp(page); } /** * Turn log view on or off */ public void logToggle() { if (gameScroller.getVisibility() != VISIBLE) gameScroller.setVisibility(VISIBLE); else gameScroller.setVisibility(GONE); } /** * A new game was stared, we are given the information about the game setup * @param cards Cards that are in play * @param players Names of players */ public void newGame(MyCard[] cards, String[] players) { GameTableViews.clearCards(); openedCards.clear(); moneyPile.clear(); vpPile.clear(); supplyPile.clear(); prizePile.clear(); nonSupplyPile.clear(); hand.clear(); played.clear(); island.clear(); village.clear(); trash.clear(); this.players.clear(); actionText.setText(""); gameScroller.clear(); gameScroller.setNumPlayers(players.length); gameOver.setVisibility(GONE); gameOver.removeAllViews(); // FIX: After playing two games in a row, winners of both games are displayed without this fix. gameOverScroll.setVisibility(GONE); tr.setVisibility(VISIBLE); for (MyCard c : cards) addCardToTable(c); for (String s : players) addPlayer(s); boolean platInPlay = false; for (MyCard c : cards) if(c.originalSafeName.equals("Platinum")) { platInPlay = true; break; } boolean colonyInPlay = false; //check if there's a colony for (MyCard c : cards) if(c.originalSafeName.equals("Colony")) { colonyInPlay = true; break; } boolean potionInPlay = false; // check if there's a potion for (MyCard c : cards) if(c.isPotion) { potionInPlay = true; break; } // adjust size of pile table if(potionInPlay && platInPlay) moneyPileGV.setNumColumns(5); else moneyPileGV.setNumColumns(4); if(!colonyInPlay) vpPileGV.setNumColumns(4); else vpPileGV.setNumColumns(5); short nonSupplyCardsInPlay = 0; for (MyCard c : cards) { // More types to check for eventually... if (c.originalSafeName.equals("Spoils") || c.originalSafeName.equals("Mercenary") || c.originalSafeName.equals("Madman")) { ++nonSupplyCardsInPlay; } } if (nonSupplyCardsInPlay > 4) { nonSupplyPileGV.setNumColumns(nonSupplyCardsInPlay); } else { nonSupplyPileGV.setNumColumns(4); } // done setting up, remove splash screen top.nosplash(); // log start of game gameScroller.setGameEvent(top.getString(R.string.game_loaded), true, 0); } /** * initialize a card pile for the table * * This is called upon setup from within newGame * * @param c cart type */ public void addCardToTable(MyCard c) { GameTableViews.addCard(c.id, c); if (c.pile == MyCard.MONEYPILE) moneyPile.addCard(c); else if (c.pile == MyCard.VPPILE) vpPile.addCard(c); else if (c.pile == MyCard.SUPPLYPILE) supplyPile.addCard(c); else if (c.pile == MyCard.PRIZEPILE) prizePile.addCard(c); else if (c.pile == MyCard.NON_SUPPLY_PILE) nonSupplyPile.addCard(c); } /** * Make the 'select' button clickable. Call this when the current selection of cards is valid, e.g. enough cards selected. */ private void canSelect() { select.setEnabled(true); } /** * Make the 'select' button not clickable, if selection of cards is invalid */ private void cannotSelect() { select.setEnabled(false); } /** * Is the given card an acceptable choice given the constrains saved in sco? * @param c chosen card * @param parent which pile the card was selected from * @return */ boolean isAcceptable(MyCard c, CardGroup parent) { if (sco.fromHand && (parent != hand)) return false; else if (sco.fromTable) { // if (!sco.allowEmpty) { // if (lastSupplySizes[c.id] == 0) // return false; // } if (sco.fromPrizes) { if ((parent != vpPile) && (parent != moneyPile) && (parent != supplyPile) && (parent != prizePile) && (parent != nonSupplyPile)) return false; } else { if ((parent != vpPile) && (parent != moneyPile) && (parent != supplyPile)) return false; } } else if (sco.fromPrizes) { if (parent != prizePile) return false; } return sco.checkValid(c, getCardCost(c)); } /** * Save the state of what kind of cards we may currently select */ SelectCardOptions sco = null; /** * firstPass is true if the user clicked 'pass' once already and is asked if he is sure right now. */ boolean firstPass = false; boolean canClick = true; String prompt = ""; private int[] lastSupplySizes; private int[] lastEmbargos; void resetButtons() { CharSequence selectText = select.getText(); pass.setText(selectText.subSequence(0, selectText.length()-1)); selectButtonState(); actionText.setText(prompt); canClick = true; } /** * Something was declined and we ask if the user is really, really sure */ void passButtons() { select.setText(pass.getText() + "!"); pass.setText(R.string.confirm_no); actionText.setText(R.string.confirmation); for (CardInfo ci : openedCards) { CardState cs = ci.cs; cs.opened = false; cs.order = -1; cs.indicator = sco.getPickType().indicator(); ci.parent.updateState(ci.pos, cs); } openedCards.clear(); canClick = false; canSelect(); } /** * One of the two buttons was clicked * @param b Button that was clicked */ public void cardSelected(Button b) { if (sco == null) return; if (b == select) { if (firstPass) { // 'yes, we want to decline', send empty selection. // if 'firstPass' is true, we already checked that an empty selection is valid top.handle(new Event(Event.EType.CARD) .setInteger(0)); } else { // We selected cards and now send a CARD event. int[] cards = new int[openedCards.size()]; for (int i = 0; i < openedCards.size(); i++) { CardInfo ci = openedCards.get(i); if (!isAcceptable(ci.cs.c, ci.parent)) return; cards[i] = ci.cs.c.id; } if (sco.getPickType() == PickType.SELECT_WITH_ALL && openedCards.size() == 0 && !select.getText().toString().endsWith("!")) { // Hack to notify that "All" was selected top.handle(new Event(Event.EType.CARD) .setInteger(1) .setObject(new EventObject(new int[] { -1 }))); } else if ((sco.getPickType() == PickType.PLAY_IN_ORDER || sco.getPickType() == PickType.PLAY) && openedCards.size() == 0 && !select.getText().toString().endsWith("!")) { // Hack to notify that "All" was selected top.handle(new Event(Event.EType.CARD).setInteger(1).setObject(new EventObject(new int[] { -1 }))); } else { top.handle(new Event(Event.EType.CARD) .setInteger(openedCards.size()) .setObject(new EventObject(cards))); } } } else if (b == pass) { if (!sco.isPassable()) return; if (firstPass) { firstPass = false; resetButtons(); } else { firstPass = true; passButtons(); } return; } else return; // we accepted or declined => remove selection markers, make buttons invisible for (CardInfo ci : openedCards) { CardState cs = ci.cs; cs.opened = false; cs.order = -1; cs.indicator = sco.getPickType().indicator(); ci.parent.updateState(ci.pos, cs); } openedCards.clear(); sco = null; pass.setVisibility(INVISIBLE); select.setVisibility(INVISIBLE); firstPass = false; resetButtons(); } /** * Prompt the user about options that a card gives us. (E.g. Thief: Which card to trash) * @param title Message to the user about what to choose * @param options Options that the user has */ public void selectString(String title, String[] options) { if (options.length == 1) { Toast.makeText(top, title + ":\n" + options[0], Toast.LENGTH_LONG / 2).show(); top.handle(new Event(Event.EType.STRING).setString(options[0])); return; } HapticFeedback.vibrate(getContext(),AlertType.SELECT); new SelectStringView(top, title, options); } /** * RemotePlayer wants us to choose card(s) * @param sco What kind of cards to choose, and what for * @param s Prompt to display * @param maxOpened How many cards may be selected * @param exactOpened May we choose less than the max number of cards? */ public void selectCard(SelectCardOptions sco, String s, int maxOpened, boolean exactOpened) { this.sco = sco; this.maxOpened = maxOpened; this.exactOpened = exactOpened; prompt = s; firstPass = false; resetButtons(); HapticFeedback.vibrate(getContext(),AlertType.SELECT); select.setVisibility(VISIBLE); if (sco.isPassable()) { pass.setVisibility(VISIBLE); pass.setText(sco.passString); } else pass.setVisibility(INVISIBLE); selectButtonState(); } /** * Update the 'state' (grayed out or not, text) of the select button, when a card was (un)selected. */ protected void selectButtonState() { if (sco == null || sco.pickType == null) { setSelectText(PickType.SELECT); canSelect(); return; } // nothing picked yet if (openedCards.size() == 0) { setSelectText(sco.pickType); if (sco.pickType == SelectCardOptions.PickType.SELECT_WITH_ALL) { canSelect(); } else if (sco.pickType == SelectCardOptions.PickType.PLAY && maxOpened == 1 && sco.allowedCards.size() == 1) { canSelect(); } else if (sco.pickType == SelectCardOptions.PickType.PLAY_IN_ORDER && maxOpened == 1) { canSelect(); } else { cannotSelect(); } // update indicator for default play action card if (sco.defaultCardSelected != -1 && sco.fromHand) { int pos = hand.getPos(sco.defaultCardSelected); if (pos != -1) { CardView cv = (CardView) hand.getView(pos, null, null); cv.setChecked(true, sco.getPickType().indicator()); CardInfo ci = new CardInfo(cv.getState(), hand, pos); openedCards.add(ci); hand.updateState(pos, cv.getState()); } } else { return; } } // something picked if (sco.pickType == SelectCardOptions.PickType.SELECT_WITH_ALL) { setSelectText(PickType.SELECT); } else if (sco.getPickType() == SelectCardOptions.PickType.PLAY_IN_ORDER) { setSelectText(SelectCardOptions.PickType.PLAY); } else { setSelectText(sco.pickType); } if (exactOpened && (openedCards.size() != maxOpened)) { cannotSelect(); } else { canSelect(); } } /** * Sets the button text corresponding to why the user has to pick cards * @param key PickType */ public void setSelectText(SelectCardOptions.PickType key) { indicator = key.indicator(); String text; switch (key) { case SELECT: case SELECT_IN_ORDER: text = top.getString(R.string.select_button); break; case SELECT_WITH_ALL: text = top.getString(R.string.all_button); break; case PLAY: case PLAY_IN_ORDER: text = top.getString(R.string.play_button); break; case BUY: text = top.getString(R.string.buy_button); break; case DISCARD: text = top.getString(R.string.discard_button); break; case KEEP: text = top.getString(R.string.keep_button); break; case GIVE: text = top.getString(R.string.give_button); break; case TRASH: text = top.getString(R.string.trash_button); break; case UPGRADE: text = top.getString(R.string.upgrade_button); break; case MINT: text = top.getString(R.string.mint_button); break; case SWINDLE: text = top.getString(R.string.swindle_button); break; default: text = ""; break; } select.setText(text); } /** * Prompt user about ordering cards (mostly to put them back on the deck in an order of his choosing) * @param header Message to the user * @param cards Indices into the cards the user should put into order */ public void orderCards(String header, int[] cards) { String name = GameTableViews.cardsInPlay.get(cards[0]).name; boolean allequal = true; for (int c: cards) { if (GameTableViews.cardsInPlay.get(c).name != name) { allequal = false; break; } } if (allequal) { int[] is = new int[cards.length]; for (int j = 0; j < cards.length; j++) { is[j] = j; } top.handle(new Event(Event.EType.CARDORDER).setObject(new EventObject(is))); } else { HapticFeedback.vibrate(getContext(),AlertType.SELECT); new OrderCardsView(top, header, cards); } } /** * Display the numbers of pile sizes for the card piles on the 'table' * @param supplySizes Sizes of piles * @param embargos number of embargos */ public void setSupplySizes(int[] supplySizes, int[] embargos) { moneyPile.updateCounts(supplySizes, embargos); vpPile.updateCounts(supplySizes, embargos); supplyPile.updateCounts(supplySizes, embargos); prizePile.updateCounts(supplySizes, embargos); nonSupplyPile.updateCounts(supplySizes, embargos); } /** * Is executed instead of setStatus if the gs.isFinal flag is set. * * This gets executed /for each player/. * * @param gs */ public void finalStatus(GameStatus gs) { if (!gs.isFinal) // does not happen as far as we know return; int maxVP = 0; int minTurns = 10000; /** * The player(s) to show as winner */ ArrayList<Integer> winners = new ArrayList<Integer>(); for (int i=0; i<players.getCount(); i++) { //winners are calculated in this loop if (gs.handSizes[i] > maxVP) { winners.clear(); winners.add(i); maxVP = gs.handSizes[i]; minTurns = gs.turnCounts[i]; } else if (gs.handSizes[i] == maxVP) { if (gs.turnCounts[i] < minTurns) { winners.clear(); winners.add(i); minTurns = gs.turnCounts[i]; } else if (gs.turnCounts[i] == minTurns) winners.add(i); } } try { if(!finalStatsReported) { finalStatsReported = true; ArrayList<String> pl = new ArrayList<String>(players.getCount()); for(int i=0; i < players.getCount(); i++) { pl.add(gs.realNames[i]); } achievements.gameOver(pl, winners); } } catch(Exception e) { e.printStackTrace(); } boolean won = false; for (int i : winners) if (i == gs.whoseTurn) won = true; tr.setVisibility(GONE); gameOver.setVisibility(VISIBLE); gameOverScroll.setVisibility(VISIBLE); @SuppressWarnings("deprecation") LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); FinalView fv = new FinalView(top, this, gs.realNames[gs.whoseTurn], gs.turnCounts[gs.whoseTurn], gs.embargos, gs.numCards[gs.whoseTurn], gs.supplySizes, gs.handSizes[gs.whoseTurn], won); fv.setLayoutParams(lp); showCardsButtons.add(fv.showCards); gameOver.addView(fv); } void uncheckAllShowCardsButtons() { for (ToggleButton t : showCardsButtons) t.setChecked(false); setSupplySizes(this.lastSupplySizes, this.lastEmbargos); } /** * User got an achievement * @param achievement Achievement name */ public void achieved(String achievement) { try { achievements.achieved(achievement); } catch(Exception e) { e.printStackTrace(); } } /** * The RemotePlayer updated us about the setup of the game, and we display the changes to the user. * @param gs GameStatus object contains all this information * @param s ?? don't know yet ?? * @param newTurn ?? don't know yet ?? */ public void setStatus(GameStatus gs, String s, boolean newTurn) { if (s != null) gameScroller.setGameEvent(s, newTurn, gs.isFinal ? 0 : gs.turnCounts[gs.whoseTurn]); if (gs.isFinal) { HapticFeedback.vibrate(getContext(),AlertType.FINAL); finalStatus(gs); return; } if (players.getCount() <= gs.whoseTurn) { for (int i = players.getCount(); i < gs.whoseTurn; i++) addPlayer("--"); addPlayer(gs.name); } else { PlayerSummary ps = players.getItem(gs.whoseTurn); ps.name = gs.name; } if (newTurn) { myTurn = gs.whoseTurn == 0; if (myTurn) HapticFeedback.vibrate(getContext(),AlertType.TURNBEGIN); } turnStatus.setStatus(gs.turnStatus, gs.potions, myTurn); for (int i=0; i<players.getCount(); i++) { players.getItem(i).set(players.getItem(i).name, gs.turnCounts[i], gs.deckSizes[i], gs.handSizes[i], gs.numCards[i], gs.pirates[i], gs.victoryTokens[i], gs.guildsCoinTokens[i], gs.whoseTurn == i); } players.notifyDataSetChanged(); actionText.setText(""); if(newTurn) { String header = top.getString(R.string.played_header); if(!myTurn) { header = players.getItem(gs.whoseTurn).name + ":"; } playedHeader.setText(header); } GameTableViews.newCardGroup(hand, gs.myHand); GameTableViews.newCardGroup(played, gs.playedCards); GameTableViews.newCardGroup(island, gs.myIsland); if (gs.myIsland.length > 0) { islandColumn.setVisibility(VISIBLE); } else { islandColumn.setVisibility(GONE); } GameTableViews.newCardGroup(village, gs.myVillage); if (gs.myVillage.length > 0) { villageColumn.setVisibility(VISIBLE); } else { villageColumn.setVisibility(GONE); } GameTableViews.newCardGroup(trash, gs.trashPile); if (gs.trashPile.length > 0) { trashColumn.setVisibility(VISIBLE); } else { trashColumn.setVisibility(GONE); } this.lastSupplySizes = gs.supplySizes; this.lastEmbargos = gs.embargos; costs = gs.costs; supplyPile.updateCardName(gs.ruinsID, gs.ruinsTopCard, gs.ruinsTopCardDesc); supplyPile.updateCardName(gs.knightsID, gs.knightsTopCard, gs.knightsTopCardDesc, gs.knightsTopCardCost); setSupplySizes(gs.supplySizes, gs.embargos); setCardCosts(top.findViewById(android.R.id.content)); } static int getCardCost(MyCard c) { if (c == null) return 0; if (costs != null && c.id < costs.length) return costs[c.id]; return c.cost; } private void setCardCosts(View v) { if (v instanceof CardView) { ((CardView) v).setCost(getCardCost(((CardView) v).getCard()), ((CardView) v).getCard().isOverpay); } else if (v instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) setCardCosts(((ViewGroup) v).getChildAt(i)); } } private void addPlayer(String name) { players.add(new PlayerSummary(name)); } /** * A player obtained a card and we notify the user * @param i card index * @param s player number, as a string * @return a message, either something like 'card obtained' from resources, or "<playername>: <cardname>" */ public String cardObtained(int i, String s) { return top.getString(R.string.obtained, showCard(i, s, CardAnimator.ShowCardType.OBTAINED)); } /** * A player trashed a card and we notify the user * @param i card index * @param s player number, as a string * @return a message, either something like 'card trashed' from resources, or "<playername>: <cardname>" */ public String cardTrashed(int i, String s) { return top.getString(R.string.trashed, showCard(i, s, CardAnimator.ShowCardType.TRASHED)); } /** * A player revealed a card and we notify the user * @param i card index * @param s player number, as a string * @return a message, either something like 'card revealed' from resources, or "<playername>: <cardname>" */ public String cardRevealed(int i, String s) { return top.getString(R.string.revealed, showCard(i, s, CardAnimator.ShowCardType.REVEALED)); } public String cardRevealedFromHand(int i, String s) { return top.getString(R.string.revealed_from_hand, showCard(i, s, CardAnimator.ShowCardType.REVEALED)); } /** * Notify the user of a card played/revealed/... by a player. * @param card card index * @param playerInt player number, as a string * @param type how to show the card * @return "<playername>: <cardname>" */ public String showCard (int card, String playerInt, CardAnimator.ShowCardType type) { int player = 0; CardView c = GameTableViews.getCardView(top, this, card); try { player = Integer.parseInt(playerInt); } catch (NumberFormatException e) { return ""; } View anchor = deckStatus.getChildAt(player); if (anchor != null) { animator.init(anchor); c.setOnTable(false); animator.showCard(c, type); } return players.getItem(player).name + ": " + c.getCard().name; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { CardView clickedCard = (CardView) view; if (clickedCard == null) return; if (sco == null) return; if (!canClick) return; if (clickedCard.isChecked()) { HapticFeedback.vibrate(getContext(), AlertType.CLICK); for(int i=0;i<openedCards.size();i++){ CardInfo ci = openedCards.get(i); if(ci.cs == clickedCard.getState() && ci.pos == position) { // this is the card we clicked openedCards.remove(i); ci.cs.indicator = sco.getPickType().indicator(); ci.cs.order = -1; ci.cs.opened = false; clickedCard.setState(ci.cs); selectButtonState(); break; } } } else { if (isAcceptable(clickedCard.getCard(), clickedCard.parent)) { HapticFeedback.vibrate(getContext(), AlertType.CLICK); if (openedCards.size() >= maxOpened) { CardInfo ci = openedCards.get(0); ci.cs.opened = false; ci.cs.order = -1; ci.cs.indicator = sco.getPickType().indicator(); ci.parent.updateState(ci.pos, ci.cs); openedCards.remove(0); } clickedCard.setChecked(true, sco.getPickType().indicator()); CardInfo ci = new CardInfo(clickedCard.getState(), (CardGroup) parent.getAdapter(), position); openedCards.add(ci); selectButtonState(); } } if (sco.ordered) for(int i=0;i < openedCards.size(); i++) { CardInfo ci = openedCards.get(i); ci.cs.opened = true; ci.cs.indicator = sco.getPickType().indicator(); ci.cs.order = i; ci.parent.updateState(ci.pos, ci.cs); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { CardView clickedCard = (CardView) view; return clickedCard.onLongClick(clickedCard); } }