From 166c3f38e66bb1d9574f6c88075c49703370ed73 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 28 Dec 2015 07:33:03 +0100 Subject: [PATCH 001/141] 6.01 Gear - bad text fixed Save - Only once per turn fixed --- androminion/AndroidManifest.xml | 4 ++-- androminion/libs/vdom.jar | Bin 2256729 -> 2256794 bytes .../com/mehtank/androminion/ui/Strings.java | 1 - vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 1 + 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/androminion/AndroidManifest.xml b/androminion/AndroidManifest.xml index 207bb2eaf..f52738a33 100644 --- a/androminion/AndroidManifest.xml +++ b/androminion/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="601" + android:versionName="6.01" > J%Jgpt49Y@_tyb2<4%}%%F2-Gg~Fb zIK*w9Da?WMG0_P=SV00hCx~(LF*VW62$*aMBU>a3bA~u~T8dzs@7{dhdHw%6=RSC} zi#yoAixVs<}CR=MW?gfp-W}hahtZUJl_khah(d-VVX1P4MlBmn3#L z@5KAANs=da)F%&DHeGj`cKYu5o0B=awhHg5qw`}`o_h9q*d6g5)MlO`jR!S7XM#5x9jef~Pn;QUa8YoRiy>hd+~JnPT`mRga~62O<-jkT9UgI;pr6}LZwEYf-l&o{^hKl39DIv%;l7s$G!=VKvRq+7#&&6EGsTw=3Xur%oLgyEfRX5y}3V>VkYsr(C@vKd2l4x7i{9#tck z%Vwgb%14f^85F-akK%XduwcIPncEnSH*=UtGMnF@%QB?feKmlCqcX#OLF0}4qb4FS zmnwd$^ce9IrN#?i*q9QBT!t|1gkeST#5ES@v0%vz1GeTdBev><$@&KFF1F;cG)Y9b z%NmM{vM5nhJ~Qx@6NT%Abq}&G;^FzkEbnkGr>w)m19CP z$LeHgv9buh6Lomzf-Vs2tZY92VS}4#v86%hhr?E8=IxCh$@H7fA2&AYyl_<^1#Uay z(KjB^X)(Wu?$udHz3%=}<3|GQ4<%B#k{B66;6^XT1eR8Nse zCsnSXsfDg1?g&&)p{?~W>C6I7V3_+POnrKvwx)a7{W2EKv(G$iPC0pM`H=C% zNof4hzaa|zk6b0X zF*H}Qd_G!gbk&L(Z=rj-*>)y?|J8(eRWqi zaF@C^aFS=bAjX1TuZQ}E*CkcrREbw5L6t;R3Q;AUDh*O4y()#OQrICW{G^*#Y62JB z;d7?ym74A8u(Nhwz_~7b<1J1fXk8&y$@=n5+tbJGS0`7yYovg?Cc^)$Fm{9kd%7Yl z*fBIBw7R1`f)GiFA{YpR3DJa@Ku3FQTeWsYtw;V|h|sQRNy!uI<^t3OD(1+~yF%N6 z2LS+bG4O_*6VXgR1u)V#13eB?FXMg9hOintR#fK>Pp#=%~g0F5vi_Q6!x4<7g!is2I|g-_vC_zc#<0oVu!0U1mCIZ@8osIK#Q%TW&Ob$EA{x z2IskHaDkf+7da1fatq)R=ZBxUSD=eqMXL%uf$nO#ghgrvUUhJtH_8GKWx-LsMj3rh zNeZlJl-)7tI4nnD+Vt4)YF(R5FcK6(93h@yBA5vlf|Xz+*a?n+t}UT*8DHNJSe?TB zcC7U?5&y_w)3B+GiK5nOoRG=f=qe?uwK%Xglf{Gtjdk1=SYS2`~HV_&^F5=Z1S z7ytCGptAH=b2K*XGV8D=pUN|ScTjHHZH~ho1(d@-`OL(td-~*<+|W4En4W` zwnw2D+>lSFnF>iZp3r0&9Uqxv(OXEj(~uXkDcm~zv5>te+?r#-jJcK}m{!D+g`cwf znGN46qLIq>S^7sR=~3~dU@muyXs+%S2BS6{yO7#B?CSwa(?1xuEu{XBx?{nbJC=C7 zXB1tseC)+vEYC+2)s$@6d%tdSxXT{C52sxEjJeI*?aF;7m#6QU)gl&FOTD{pC zf)k3Vi;eGD0S)(QfX5dN{8@GsQ(l$>1A)uM%qhsNR&4e&N~F~qhADn}${Xh%OCh+% z&qnh93E1RknS8rlTZdqGv`xg}CDhdNshVQNWhHD3ziL*HoGxLbdHY=Sl#D- z?XEon-DR}(@;yz-<^LA2qm1SA&qZr%A~wm6NE|eS8osie8m`7^@=$Ckr#%(dgCu$h Yy*A#&NlVyRt^k)WVHTY$h0&Yme*xZ6hX4Qo diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 134432943..899ab2201 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1154,7 +1154,6 @@ private static void initActionStrings() { getCardName(Cards.artificer), getCardName(Cards.bonfire), getCardName(Cards.dungeon), - getCardName(Cards.gear), getCardName(Cards.storyteller), getCardName(Cards.treasureTrove) )); diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index e89ae32c5..d29f6156e 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -703,7 +703,7 @@ public enum Type { actionCardsAdventures.add(artificer = new ActionCardImpl.Builder(Cards.Type.Artificer, 5).addCards(1).addActions(1).addGold(1).description("Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck.").expansion("Adventures").build()); actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 3).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is on play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 2).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); - actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 5, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); + actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); actionCardsAdventures.add(dungeon = new ActionDurationCardImpl.Builder(Cards.Type.Dungeon, 4).addCards(2).addActions(1).description("Discard 2 cards. At the start of your next turn: +2 Cards, then discard 2 cards.").expansion("Adventures").build()); actionCardsAdventures.add(duplicate = new ActionCardImpl.Builder(Cards.Type.Duplicate, 3).isReserve().description("Put this on your Tavern mat. ~ When you gain a card costing up to 6 Coins, you may call this, to gain a copy of that card.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 2df7b79ac..0cc288dba 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -151,6 +151,7 @@ private void save(MoveContext context) { context.player.hand.remove(card); context.player.save = card; } + context.cantBuy.add(this); //once per turn } private void scoutingParty(MoveContext context) { From 5bf715583103a8bd200fa973f8054bffd33c67f5 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 28 Dec 2015 08:54:07 +0100 Subject: [PATCH 002/141] exchange: ordered and if pile is empty you can't exchange --- androminion/libs/vdom.jar | Bin 2256794 -> 2259187 bytes vdom/src/com/vdom/core/Player.java | 4 ++++ vdom/src/com/vdom/core/Util.java | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/androminion/libs/vdom.jar b/androminion/libs/vdom.jar index f671b43286e3dcfc8bb24cd30be445b05b883b73..feecbefe933335437b74fb644e6367e991236bda 100644 GIT binary patch delta 18839 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 UHHi=0;WYj?r2{}wJ3Hq77cbCoy#N3J delta 17718 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 UnDFEU;3WR_!$X?M&1~5EKRR0*PXGV_ diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index ec2c36b6f..2605a876e 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -447,6 +448,7 @@ protected void cleanup(MoveContext context) { } + Collections.sort(playedCards.toArrayList(), new Util.CardTravellerComparator()); while (!playedCards.isEmpty()) { discard(playedCards.remove(0), null, context, false, true); } @@ -896,6 +898,8 @@ private Card traveller_exchange(MoveContext context, Card card) { if (card.equals(Cards.treasureHunter)) exchange = Cards.warrior; if (card.equals(Cards.warrior)) exchange = Cards.hero; if (card.equals(Cards.hero)) exchange = Cards.champion; + if (context.getCardsLeftInPile(exchange) <= 0) + exchange = null; if (exchange != null) { if(!controlPlayer.traveller_shouldExchange(context, card, exchange)) exchange = null; diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 61f56a1c6..2b0af7294 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -648,6 +648,33 @@ public int compare(Card card0, Card card1) { } } + /** + * Comparator for sorting cards. + * Traveller cards first, rest unsortet + */ + static public class CardTravellerComparator implements Comparator { + @Override + public int compare(Card card0, Card card1) { + if(card0.isTraveller()) { + if(card1.isTraveller()) { + if(card0.getCost(null) > card1.getCost(null)) { + return -1; + } else if(card0.getCost(null) < card1.getCost(null)) { + return 1; + } else { + return 0; + } + } else { + return -1; + } + } else if(card1.isTraveller()) { + return 1; + } else { + return 0; + } + } + } + /** * Comparator for sorting cards by cost and then by name * Used for sorting on table From 1f38e3afd7ca1053ddc56b7ca596cb3e72f23b79 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 28 Dec 2015 09:25:45 +0100 Subject: [PATCH 003/141] princed travellers left the play by exchanging --- androminion/libs/vdom.jar | Bin 2259187 -> 2259901 bytes vdom/src/com/vdom/core/ActionCardImpl.java | 20 +---------------- vdom/src/com/vdom/core/Player.java | 24 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/androminion/libs/vdom.jar b/androminion/libs/vdom.jar index feecbefe933335437b74fb644e6367e991236bda..4edf5c5e675d8312290cf6a39afca1207304294e 100644 GIT binary patch delta 129858 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%0Ax(}jbF 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[qJ~)<%&Ph9fsmq@n=&mK2S;6zE%d!hhND$ zpyJG(QE`%{iAjhfb(xb;q{t*BKD_t`FIVD9FE>=a+%W6qMj|?T`sKy|q+f0vK<4F! zre6-i@a1opnH>MYd*!6xD`hoWjeUWM^1UXT@8$Ujk%rUnH4Py1Diim>a_aJSvXfD6 zl7`b6Y_yh5&cA3Jv`g-lo#}(zssmRNeldgmnfNj zi6TAcR{0Y1te04b^H|n%_XQRMq(9D50PFSo><`?U{y5^>_=|O&fBtdE7FdQKVGAq| ztN?uq$9uNW#=uG#Q~l(4J8)N%1k_MU;BHa__mG__eWv`(>FRD82Pf*;-sLnuu)0aM z=OE}B&=*11;(ls6F78Ff2B7PZa0YZe@MO>pO|qSDgKlh+?fMFIQ($<{7p$9kQ?6GsU0b6o32VYFwp3_!b zJo-S6>f}4mKAiKR$g_Qa&M9#*?@&$;k>|a~a$1Nyc~9ny6n7Rsn-dooTVBZdS|qJ_ zE$8^P{`IZawJtkiXU@9rMC%SsRCAYhF_!hp%`tNN=5{nL^~$Yu+ls!q_$!IOQur&4 zzq~^$`j+|ZBipQYhi2DLs=9qvyLHCGF3FZ2T(mA*dBhguM3-a}Kcnbd%bLFUJ<*Fs zUf1Ncr6=N6WA$+R^2Zh8Kb-$A^4}N64PBEJ%5b^qFFZ5AfC(i3RVgOwrAlZY7KbxVfDD_q~_@h;m@8~;@< zR%7*>tpcy#=!uGV7BzZCzW$am>7 zxGova<5qj}lYl~`2?|FK{P~_mh;<;umx2iq5AmB50cDH`i zigr)*8jQ^RSG+*pJ+i>7HlOjkEb#WZH-CH#nfb4Lu@`@Kja8t={c*3+rHA!|59ZXo zV+u~Z@L#231)knu73i|T<2PF4mx^W^P-BJPINAfvcH@0khHrZ$%ZuOl)SX9nuf~)4 zulVZ@yWh$?Xd`}Ky0TYyJh0iA+!K{GeaOnNsb{jZsBB8zYMZB_BK|A>LCfv8^1k|< zEs&|qI2CDUlXbfzVYkH&i)M!i1CeEaV+yoQn&(2eDjyg@^o2;W~v zhbJ|o-xRL~*QfHo8)p~ImRCQ=WqilQ%idb_ew+TukkPGgvXtY%0xucoe|74{;=aim zj{c`4e4}r&y5n@)EHYM1^d^jw{gO3oHJ2Nm`z2f2o3HU1UHT<;V^_aqHOD7;0WvnP z%gQmnNd#QRrGCkL#|`D>J${sjd2Q(_(Hvt)|76S-1_$q-EM+^8j}Vj2ik6)WxPHh+0)i- z0n>^`=Yh#;_F=1|#@>6PRgGN((K6lFM~%&Eqt%SH;7ms0#%Pp{p{@UJ+G5-?D4AMwyLSr7|yX{4ofPIm&M)#Ef71CBsIW!MN9@s=Rm0VARo|hp~5X zvWG3)hiOSO<26H)rEEVxWZn_qW&!RvX1#=>U24Tk7!|spI;~OCVZ1#gS;A4eL(EDD z4n>{AJ~f&QO?I>&KN~alejF=l>>iq|X1nP#qsH~gq;ZL}l>dQ27yII0W5$yclX0WQ z&p1&k+g>xCyFOXMKJ|}GV$cwMM;nF~`otYi7YZ8U{q{7$yWB7=S;AIZGnx)h<{3{M zD5)Bc4?{0$uk#&D>%;NjQ*iz;JlWatelkwRt!3h+j8b_4(RK43ODo8Gz7gnqA6JoZ z;0TobvbwQsM6#!2TP@t~S}mS1?&^b9INBOdzPE2&3&?LoG+=PU2kU*{SVM&T73jzVIi(+oN}p1(E+)n1cRKHUmFIrpc@StXB?e~J{263TZD%hohD)= zUz)^eWsGGLk+J%l3_9Dcu^XXD$riReH`9pG$XznaSneq4GH#rd%(tEO89OE=o7u`X zGtNy)Hgyc0R}$mpfGuXUnvADw>m^)18I|sN$ar#cvWqSG1k*A`ttnt@IWLqn%2Y0u zYutXUq}Nz71ta&z)7Gt%Q<6394y_btNE%hACac?Dts+nbWByb;e_A(V&(vgB+q`~E zlScVzsImMIktNrdGA&u#{@F$g9h;V{Wjh@(o}7+Hckz|ZHd$x0>GuyfN+uu)pPXjCD68Yn2^!ZIXsgA3bhZ awHwBd>(buo;!gS`{x`WHQJqFS$^0L9oZMLe delta 129704 zcmbrm2Y6J)_b@!=-a9jQCrd(lgAjTWdJnz#-lZC`}L$1Q|dD!GaBi z00{^RSU^QZY={l{iDDP*D8hH1XD--U>VK&nzn~rbS9FyBfnMU5(VP5F^a1}1eZ;SzFZkc+TYeS&#;;*45S9Yt zctLQwpty-JaC>3mp2EUI1jFM6$GIUPa8TIzX5qn0gv4t^1invr@uQ*!-Yp{WArXa- zi)j3sh{JD)B>b*O#^*!|z9>@hWl@WmqBfBtjUm}CURWTR9}G3JV? z#$qweSSE6e^&-#MCT181MZh>JW*TpaS;krT{#q0omqpNw7DZ;Fm~Ezr60?mcHM@y2 zvnRv{i}~g-akDu^++ya7Tg`c5fw@H7X08MHeL(k!SY+-Ki_H@vw8VU0EH(clmYY9` z6_yltSvAE^~FJ=P=$r;GL09C5D|5*w^LgtFF%jn;i)ll73; zY&|OOvkr*+t)l>cRcy1q6Wgs{#6!#$53?BY2up={L$QNpipN<;@dWE4o?_!dVkcW6 zo@T4WGi(h2Hj6!MtJuq)68qS0QNd1%O7^MP&(4Ww*;nFu_J=sku8Jd^i5GaPc#+o^ zFYzW2Zzo>iUBzp>pE$uMi8uIMagyII-r{$PQ+%~}n{R;cE#f`?w0NH%6{q>T;sbtO zoZ+FX;zMDGk3_UMBT~gV(Nz3Lv=^U?uHwAtE4~l|#04=$f} z56<-$muTqg(t1Nfc~NnoFvnlw08dKmEe-UP7MGQj&L3Io_vdQlx25$?9f!v>U*6E^ zeS`VA+={pFfvO@eI+xrkRM6wV{#HBJI7a?+rO}{ zufQ+RR_jw~okfj6sF6kfoWS&eKi9U-S)ViOKN!WTlTX^QrnJsmU#M=sm_6&Avo1*M zD~(?x*FW7?mS3v*jGABM*Hqs~>s#wPwc{7FVXbr4kJ7qGnnD@!{G~m7h5nw9uP(z+ z()w9__lud>@mFd6=9F?;zAtCiU|;bpf2nPhT7O9Evh^oMw7@qHiqNQk|Hl12=1HTb z&g5@tUA3;MZoitn(y=5j;O)SaQOOKc3nMuzTrE1Y62>fb?TO?hb>vqwGSWnAK@Uto zWicD0_G3k2} zz#2-{Nb}@@l0m^B)VpAygAB~dSC|_p?ddBh(%`m|wbNi$6v)r_<@q(NgJjtn#tVGKzOr1%7=WE5 z>#TuRNl`G65B3{s&bmt0&4HB_=gbHcYP24b_0%9y;4jYc7y63lYiMuD`Z$O){KW+U zN1lF?^>;u8zT5(zLpxBiK^kNfxq=LlY^Vl!ON;%!lColdzp_HD2jDndhS&(5#^(Bp zivvLiI7+h74g<(0sIkUMHckV0&I~9o)RhL_B-sRqvIv;^!rGZ6*<=S+0*x&Y&SI)$ zK8JXESze$tFvrnNj%2wGVrj_l%Yl3}$LW&gX`ngHH!BPYNH$YLtYTkbUKo@wS%HI; z7jQETN>-#HHt0UDI8Xqk=ByZ_2&XR70)=VA@_q9;D}{#G=wyxWee2t%Vx(!up`z;H_*muoZXHQv2D&4VbouJ_BBhX zZ1<-*9plYv%U@<9-^A{h=pOcfI{cSetHV}_`l5b7KEqcsIOuaKZ@XjMY>g;ixG7)^!Lk>9kaITD)7(o`|^Qj4s;izf_;5~Lfu8YD$RG;YijA=<^<~v z$=+lq)!<#JtvrIAV(&2aHbxB<-j&*LfMoA7=u*W9-OPps^8GeDMcQbz(~^CllRWM) z;UuD4*oTsRgttSEfs+1(&^JSmFQ62ks0~-mJp8%3dey8K@gL}^$i3`KNj9h`ab zTd1km%$$1POZJ1K+hSj-9wyjD$u2p7qF`|;V?SdQw{Gg>xLVMOvR@_pE!>Ghp`f$+ zLs#5ojG8o3m;N>zNAzzz#%59MFActO?{F)Xv8$3@<4D~UAK%Ib-Ety1<>=mWYq=#P zH@K;~V{0+4xo-CEI^4sfc#Pz+>PKv4Sc#G+p>e9tMo-Krkc_8Dp6W;jeab8is4aP# z2G}{lLZ~C%)o5_K?l++7;Ja@)kxrXifdV z0`j3Mc`M0VtHIPtGTKVsPR*iLEhAg_WDG2NPlUsN6PtlHgQK42Zd2oN`;R}#JD)+^V)_v`Ny*S{ar z-)~<3-l)G%sZDuSYy7TyGtU~7_ytg`p&e*yIeLif zw?4~eiR?I%<<^%~UlrEZ2dwWg$`(6NT%tIDM`Cn@jLGI1iCnYOAcxnNiLAo<;TVd| za3cF~R7OUZy*NrEm0Oo8=&6jo7?)eW9H8Am8+hv`oL`Q11JF}J5_9Q(>-V;-9BqkZ zk@i#&1u|C81gzwwzlhGTifS{8PZWtf);?hUrOpSewD>E4nGH2#??6eKTcQXjCeO5* zW}vYeRL)2_x&VJ6rwVIGg%JfDE67kM@gOtDS2CtbW?F4cu4PqE&$QZMkNOfgSTdUd zp-P$sEx~()MOCn9)n%47(HoD^F*F3UKr#=oB=y)VD>DXQ(JZyX2y8+%GRE)4@iDBn zx-biBuZ~K|w`wJN$7YmU50#T#TEU$7qi$S{%(uq3ad@V?JRN5Bt}}}TW;y$CY_-bw zLZK>H9d$0>O2bDLDX^M?&9x}7`r!uZ<^n4zwlQ#zv}Z)xxfRx)BTQzCa+akYFR*Hb z+_EHk-1__2sUFs>O3|B8Uk75Hs)B4rZ9w=_MwRFbO2%3(Q zYoVGFw3^kPZS2R7M6(hdfGwfl58}senzA4N1|2{&D^ojzP~CIY$3ZI{->j|$tz-z2 zi>&6J+W-StMeS!dt1(5^&Xk4W?jqZx`CR@7pF33T*;WF*4cD&Bo^6>pRLSnZ&#}cY zP%goz*fRVvyAz*dci}JDO8h-rg)g$zgtEIyG+RUJvbCfYyNC2->&Qs9p5(B5NeSCP z7BNNEv5n**wu$Uvo5_ppe)0}`fPBujkT2L)@-usoQnrmov+cAldx$n<57P|x2yMk4 z4bgtAfR12K&;Waq7O|&j3EN5Mu&3#K_6%LjcF|>Q4_(Ff!gO~Z-N`EGi>#8KfcSgt zApL|LqCc@C^jCJ&kn9B`mc3{sup>q)J8sltuNV#46GjVm!f3}{H?r9qMo;#p(T|-p zhO@VgeD;n}!a{Ew3)uU{5_Z~H&CVE#eQG?w&Kl3K{}@Nu=f+#?ym5woVVq@O8h^42 zrk8zTrm}C%#_T(@8T;Ps3E>F#qdA3LGH0@%%w_CX^IrD5c|ZHZ+|DkW73@#*HTIYJ z34DLYu9`oxYnGQ?wGueBGB^xHA#PfOxn)g)Fpok%GnJ;CFwavpCT<_Xs8JkdJCldNxfvUQcGGMlHdXr9gzcwLsv8?Z*a5zFM!tPRg% zJ$X~skGEt)c`G)7w`O^~4J+Z>d$3C0 zlbz?i*hPr{$@{@hSAQ7q2lGfigeUQ#Je`l^UHK?Jh>zxD;J@+kox>;a>3kwz#3%7B zd@|n#@h7>D@8Z+=%aHmp&*k4k_&X1XWIi(_>hoEm8P69Tc!B823&mhwET-@hF`Ji) zMSPA}&2JVD@>|7|e4%)b-vL_-OT~wo`&Ue_4^3db2xgbE0b2qwf?CKFwiMMx6t$L#Y#GE1)K12+J0WJ` zSWkPl9AXx3N209GFr#5On|MhRG!A)iXX0TifQ!W42#1BXg(C1A{I;!QpywSRqjS)12PWuz^fbE*Sle_1n#fk7TF66pqFN4XY4k*+*ebRfF(V%_2gZ#f zcpSMOD46jU?nlR(Um|Xt!ClEzhza9k)E#fu{LC!WK*vH5-HHZ>fmU18g5Ay5AZ86l zk!&r9#jQKh5q1wq&8$bzQnG|BMXx&*=fH(Ot|-!wj>lHIqDZP^Xk5OfLtdZG3aKZ6+m2u0h`2==9r z1S>%(#S8(Jt_{x+VQBioq+1taVW!1QAxL2J@Lb8@~u`g{D@k8 ztCba%21s>KQ#&0sx6@DuyS_T1ksebu7FezD7}axul^NR@R)ZNR(auDT>@3t0;+^bf zYS98~NW$Z0TM%MCh_MWe5=2DJGcqgK6YA>)R(4cJ#O+R~hTR#Z+g%`+ZmRWdR?ALL zk&`abcqknKqQuN&s3s6vFom@<_nX<95u-bhVLSzi)KP$L63FhQw%=yWGW($@yT7U# zvWC~(xeHLjItrtVQQaq4aq6y+)fG2ZCqhr2{G^m^%!dVsUrHoAY>l8dJ zRU9m2kX-^=E=4WuGStSNgSy){tI+LMJU*_}?bguP+mK~LbF&vBX)kij2kcjEU1!Cr z$U9&TxlE0}!@48(E~x93D8*g{7PA^Pfp}Yct-5%JH9O*7;IIKWDB!S36)v)d)O_XN z%6~w;xyXw5yaqKQb-l0?>f$1+L+#hg*;^ItJ(%ldIn^)})Z3%UUIy^@0j~Njw(9UR zP*i|@tY$B^TC~^(#;@^!DjljMxK= zA;!7pVWCLwapZ!*5_FBPphzvFR5>fHwh?JSUI#^Z(oqdhef8){E0acWuX=Z-HMD1A z#5|cWK4$^zCMdzv6eW9_p>$7kR1aWHJ*}PWGMox;?qS6Ti0 zMGel%Jiwy~YT~Yrzs}gpwj4tdItZuefjC?&#|Ay^QLLu}N`bJxrxVKZbVhAGUDWTZ ztU5SOC9bxH@Tvx;f~zfmlkSLkdVm^w0$nfE*wY*2>w{W&`k^+S{;0EO0P5x$2$k9k z1w2C)z8m<&tGahvdxs=ABf|7Vqnsx@(FrY)rc%|UfNb5R4&Jk-@Q z9}V{0f<}67MK^hFLz6ur;J6Tsb~Y;YEK-s8z#dkn>U58l2Sas@byh900>rutL|Um% z++#JtS?cmVR%`XbJyshvZ5`~aY*1>QRhu^9P1S*QR<>;RD2mI}LuCbTsjjWFdi83P z2pe$DCe=r})(mI%&=l$$dG1HTvjx@hJcv4YwnI6$pn;x8LAu94>rbE(&y(mDh%fOx zt(L8~+Tix;x%F0k2tHqLt->AD?0c=O)IBKLvlnW9A8PHXfD%>$pMAh*4;tk;q@KMO zYOa&|_+IO?Ixj$-zlh>JFQGKg%cwo<7xwfVM?)Y!4&c)~ud7csSara3>OzZ%N8NcR z1;@3M61u=-Haw?l013L+wlXp+c{g>NvQqMTz&GJNc`pciAdZ*grM!2yMEoWGT!*mr z+?e<2mSD7kJyZCm0|5{Iu}y9WhyJ`T%*AtIMK{0_+Ka)4feE1+aO64e!{a@AzlBln zx0d0JRwdrZYNe`S7iuvztAa&TMpv-xJrN6g-`}_Wtl=peEGkv(N?v2# zk*Sv2|2U7+kjeuAUP>dLM-j$hlw=%14UOki*K*z(Kd092hzA)l_*AWj7XCGBIDdB(9i0y#*5FkDbh}*)5+pZ&)FAVU?rt^3WBVs=w z9stB=0kI;CSaBWkbi)_mFn0m}nnvsf#BxB~1BkoAh`X*M?s&Cger3};_-QI01H{Jx zafiCJ0t&K26|LvbM(KhaOgbFc02#T; z`#!eEWWb;7Xi;@r$z>&|aSj!8AfLHFQx>Kvb7&leJrg*eUU}CVzJrR%fHVb=CWVnE zU1$8)+rK7G1;$gujE}rYWaX55`8+B{0nKQj85yP-dA$G=;{#a-fkyx8hYJunE=H#x!*_x^`}cYN6AuH*GJ5$*BIp5rfu3 zbp}759rtP}5bIy#um+BdPmigbwTCaIVm#2^1hnJAl8?Jyubxs?RC%eAzf8p~fOIP$ z-5f@``Fb5Kx~KQypMkOdWrdj+-IN|*`NJV-7f}m=?slNN0|Z+H`V57uC*)L*R~zX8 zv&)g4K)cgW+scz;)SAaRQ%7Eeflw<+y|ptrRxSLD#8*yv0i=y60*14JVKFcahD#cB zO6o96SoK9r4oskOcBvna@y5nv$3tQ}kFRWXoVQJEcox5DqqF#m#DAl9a9op<@Anmh zBNDzQQFGJ+T#;aFkvL8j@fij>h*8a=U`Yu$KlpP;6@$Y<__%Blu_V49pVs(X5}|6G z8UPy;^HH0(uwqws4eM_QO9-LW<;y0XHAcK`gSw5 zhCoyBH5*DWNRq*1h{7vVTc`nF@LqV7y88=Wi+3esB^d{--U3#d^G%XWfX`>(Q+@XZ zkHeD{{gQVC#A%Y`fE=l-6C*UDUy|vhCq@bD(pJZ)gVCVM2=OBTQ}HMnLB0j~#}EJGEVv{I7&`mE8T&m`gO zw`8DyzJ@<5@%!YUI`@j15l?oI=OlR^&D7o&g{5PB`DL0xWxsEE3Kp+R^aObWqsHq_ zHAqn7rg$UOz2EWMlHVckG4d{)y*py%!%2U$p839#5=q`yO~2>0#TiZbDpZ}S(+{jS zA9hBw&r0$M`4GyIqnNfdwTPGpqzo*P%f7y}NPnq^{H<&1>OWKra7JOK60LThF{6_`3NqYI>2!4Tf|s(Ru_~JWNf2E>Mr85~b=ofs=QCVTp!$C9R=hMsC?G@J+fv zqa>}V0cLJl&W!mQ5+iA>T6>YlgyJPl&}n>5pwK@bn1G&Wl0=8mOpTZ#X{wW463Cx5 zBIqcK)|TYsaB>|<({-{n-5<;?E6^16B(1MOGB=>llDg7#*vMe&(@sJiSTDF11@l zEFvpxw1ZBPbTXZyh7R{;N25j52VE)bs-QVE2ig|RRlB>yH>R9USKWVsZHpNaKc$l~ zohea$It!y->eS)nhHBSRudSZ>g|83Ik#w%s9jo%20e#Mw^kxTELdLBwgfCm%6?*fCw(OOEoO)1O$LPC0(uo>V;oQNF28x0IZet9u25=`?1j!x?a+I(Icuwt~WM9ms3f)k#5qB^RroIf*Sf8 zACqvuqz`C9tF)}J5PT1S4BTJZQgwDkYKz*?ztioKK7<|t*5I?_9~rpWuUS1J>7!(- z`tdswH&cHWf3aqyo}vE$Pr{x)TkPoRst}l<3&&T%EISVQ)+Nj=J~W*JtOIdYQbfm z9O_Cxmh=}42E(CYYB((lMrOi+?KWSdE<)t~%Kv##_PNq^PC2rY~r zG;+b$EbK0%b=J>uU+GH!kn}PP)gAxhiM%WQOVTUwHSsS#qCJuZMy-IzS6T|rjs9Hi zu%+F-x*Aj(hUQ%(4C?M6fP)sO+CY_G{>7sj;s$D%OsJ<)>VoHWV^#DkOmp%$ji$`Z zQro^H3F@s99;NQBE8>i17^bV;Z{dy9>AE5T<~bMZiVnC<7;ViTBuee$GzKW!s|PQW zEVZGYNW>l0u6m*k?xNDp1G9zC#!F?_hrGIn0eab>x@kZ!^~{s;>1tn8LaN0~aQ1?{ zz9Ws);rfu*z%cg3`rrpXM9sbgteh$H?@tu^aBNUwh2i^&^ z0w2Vg)TqD@=+6rL=ca40a|1i%_^*r#ydHcScA!L!dUY>Bw1SvN&}xh+&}jk`ZJ4_x~yqk`1XTMEKJ!(empeN3&a4!vY} z@ykXOK4#Q`FcZIOw8STj4)}GW6Mn-O0pS#U(g@)9jeLCCSODQN{E2ZFK8uC}pD`$1 zmko_Tt@IilVmT-m#?@HZLWfZTb^wx*MQW00*vsfhwviaT01@&PemERMEz^ygNGv)C z8&vI$QFtzj0mMFJ1Bt_{HYBw>oa{?eSIB<-1_;UO$N+*dV32~B%c9UdC zwMb9cf4dEGWiZN3CMiV6)}n#n2eqO*RB&ze7zD9tkcmmxz_FB;(4xE1AW}zt*j?0b z9E0zu77t>mr6b*Qh~kZ?4CZ<1z|hIAvQZE50#2`y6dOligO=1qMNsPYpn|SY6us}k zGBW9YQcuZVA`3TE9eRmg7%Z=sh*9_S5{;4?qnR#6O9;ao?0az})Rua;muQfb@n6$p zbb3s0(Ezrd99~0vi$-ceFA=9!^%f0rlQ8sEfa0d%xYY+RvU>wYuReg$T;VJcLr4pC zM;~C*%KdDu4(rdh>dQW&2X3dj_7}10`92~_4ecx9dSsK1uCzy>f?yQ}XJvay`{b=C zBO`eqX`gir)j3EyjZcPM;BwMs2eQgZudGVacSzP=GN4HX8K`#j6`kUTqC}^x%^f=- zs3FwfFfv^I*;ll-y27C#8R2A&N2&q+M1vlq|7*S@tMVQB&wR%?`Huf*zUBS?ukxK3 z&Uca;-Cr~qG=)rc%X<<^tIr0rp>dH(o7}U#ePj|G`_Ue+AgX&Vs0itiZQ_4It!{y)8wHNL2LRu$J-A7uhvH>D%XaLL<41>(9MqLV` zXwzz+3~XCJ1TK6INiLA=K=m^Yl3C-UNkJtE!e;C2Xi`=|=4wRvs3141ivvW*=rGgq zzyw&u)&cgnX#=LoyRM+^)(7i|6nn)oO?cL9l0t z=+R&?Spvd1XAp2qtu4PTltkOHJV=&}&!|ARRg&c@d8lX*f~k2m?rM!oIOMMnCqB}+ zmE`V02gw=;?-?BK&(>8Cb%5Ll&V0rW)FKf!!tT`0d|QTqB|WH5Jdcv?n~_I{4{t(| zS&1gJwMP$-rzje$vB5QV^R*LNh6;2?wmLFYL{BLPUp}&LY!ipnh5#trW;Hngu6Ae> zO3P}Z;|H`0-;N4$$e3Eqa0jZ9)x@a&tmeNxt7b%I1vwl}Q7wmw{P-i}DCi&(oggoe z7op6}P+js8d0FinChCTckYm+}$01QyLlCiRs2(!mSe=n&jO>I{8#ti921|OY8pg;L zfHJgNC&>SS9D5D6VXt!lJcmbvYp`*A9Sm*+nln`SEB~$zJQAt{cD>N;|EdnPe7Hy% z?rQG;MOVB2sjJ_Hi&3DCu&!pix@w5JI6X2&hd>m4)WXqxQl&JFRi(6Uh+ab}H_-!?Pq!`>POat4gXg>^1dMmsMISnnE!fttZXf&#e30Rt=`f{YG zh2K%;DCmekP+6lyqqGmJ*?;7SSalZ4Gin|O+dH93M~NOuuqFgybQ`>W7#2;oSC9|X zTfi*glj`*5z)!bPaJ8r)pDOQY(I5hr?ALQq-ABWTp3^4P6o|&Um0xZ3pF_8HSgjfj zci5l;)%&AGU5Ff0S4N8jxh!nGv0!AMskAX7&T~6VJkE8_!26&V={`nuO*;=t02v5u z2e>l-L#8j(gJVR4KCmTFEz?&{$#iSdCfXtMI2=V+kgo^P&Y1_ucNkT76tUGE#f~8< z&{G^za;)e-^LuECFeyh($q!E64PX%ekz9nTxL&0l$oJ$DVCg0qhp4y)-ZSB*vlEs8 zy4^&9%&<98E!9tsRR56uXLWci^mec_QH}MR#)2iIse3!p+LitH>h2Coa9Nk&O1P^F zRhQt}kR}Hx#t3?=O{hgUeuQk#HleReG!Iain*)&PUQu^fGpf6%9U+umMG8G!(<;)3 zt4ZN@&VMJZuHyxn<k$8g8`Vx*maJzqeHa7aR%P&1$bPZbTQrh(7M z8$SO*813fO66m4<5x%d})x41l&o^iMgEY=1Z2+WkKpJ--be%S%f+kx3lri}R{A9p~ z@9L}oy%zf?dYX%#1?j;?D z)k!xnW7kUssSQAsM(()M>?W~3l;PNL6zm9VYbGcQ&8C?&3v9S2N~29^Q?RfF5Nk%8 zLrmK>c*tmrqZ!a^VicylR883eQnjs*M;@^C_$ph!Vf^WJ1B|sJ*W4bq?G50np{f(2 z&QP^elcRRoO`Ep<3w48~X-hSKf=IEvMs5XdrS6*`8q{io+JQK_tAb7(V%n_(roH;7 zr?zJ&h`tTmrfOdWm|B(74tg%9-Iy}>(N2j5sHKaZP$n9BMmcz*7*(qWN(4sWFsA2` zFpTL^0pm>AtJhmvhbO`+uc!K8qG*l#sEA3Taf0?1*YoHK+7DJ?6?BmMt%ghzJz*7i z&m>VVQ6p)ITqLwld*C}Fo}2{th6kzdCW*m#sLGxUH;IR;F_U4!9i>8(MMBgtjT%!y zoiGwY_1I+5ijJhC)Tfh0yfM0xPEeO8i#m9sN}dADrmEpJBBSfYTANTmXBGz&5$JaJ z(`hi5i>7{<$HhW{ompIPibxvLYUE;uV_B@R?b>&G$p><_wRWHmI=p&h67D9h% zpa}FI8iYa2gjL-=viel8fM=<(J~6a) z2{6>GZD-OC%Okzl6Se}}2r|&iiM4nL*nL?A8VytIayn1F?h{Sz#Z}+Slrc?YCS*3L zpz9t0Z?_>$wA0;QG$b<%KpWKPY2s$M;`P=v(Y5V;4pFy*XbQ~D@zsnt6%W$|#1`UG*a5Hoo2G80@Ur2;u zk#?z;Os&inUygKjkHZUds8+m^z64bWI>#&VQiz$bx?N6RcB<9FOX+5)E$wa7j2?rf zJV&3S8cx&Vcsi=@EY@E3iw>bqdcxZ28dROojbG0>;r}V%8>%Cu6Zp@OP7wVQdKZje z#jm-|{yWH8&-}+ZYJti-uABEU)Gu7Z6HWb}R3#GoLFlcUoE`SZkp(N*T%#5M0Il>E=WC<~?zaB$}4 z1nx9WYY<_(AOrQb4AHwX&_JM>z{n0>PU>8yh_f9&FwvyXtF)N{F70STI_)gF90JEt z%rG@_Ekkd@s)Cs!VcZAC)P3}Wa49}=6#9=+RLdXUX{xEeVM8gi0(v=E>^PtFQ|B`i zW(wyB(!EAGJ+D5QDVpO8$~#N6#NVjyvqTIIs4=rd{Ye5GUOmWbcu}%Z1JyAi;n+0_ zHHTLw+8ME^rxAzx81ZO?k&MP0wa|2M zKxd3hbRJ+o7|qoOvqYWRReJu>)pIg>*VS_nh3NMxAz##w`QGV+^dQg;aqkt>4y;fO z&j&#}spQcU_6RMKCt}Ay0igV@0^tb=Ne1HF6@ zb6upaLh1jHLco5$Yn%Tn{Ga~|A$o%leL#r5AVfb9qW}L=h`;I88-&n9LgTEAee{}B z4F+-cbed%BGt4HL2QZvcL+?ENroXvx(dz~DXD4dsrYf{ zyB4%$4Nrp>tiyC@%{r`S)YoCiXy6hwbi+o_yfs1wG;bYd8BLt9shi%+XzqNsFj_ic zE2Fg&ws8e$>*DEdMbo!;1?)hkI^WsucSk1-VWX1^==VNeB|=x`^}e z*UtBR_xolyyv41OTU`|{Fm7}3LhkoMH-p>V@D5{vP7|XkR$QyRnn5&wd@e3YSl%%V$6AvQ}yCS>SWf zr9b52KNl7-WIXR?aM*44M_dL+UHA*ei%teFg$eQ9cuh6qmx1vy7yr2Nii7v6`~8|5 zo^S##;{IDdTM?e8^w*4Jr~Sjd1*Zctv8i_-oi5dc9W2ubBbsKo#HQtj>|c2NpB<4Y zOnst?O^?f0x?x1PV5T?RY|R=*$QdNeNHfYIs2R>sJ4ZO*(P0hXufioV-BHnuHRGIg zcQk}|bDYr+7A4_=B!#VBrfxOt$_@v`(*x8I21n}OjOLkY{@IjNRpgH`)X6A2a$UFE zjAeao8-5=6N%%!n_O-q5rAEiyeP7>O`|Nq|Q>ZWf%K)$I78BEBRngo?u68x{a+Ov$ zzD8wEBX1?umkVsLk8u*UsjQ#n9cig2TYBTv>XzPAHBZNmw)Eca)jV$tebo2!-UNN# zTMcXFZDBm6-8Z|%#nx6=8pPMBe7TkPs@+VW#pqp$-qUAC-XiV1klSPaFz1ab8?8X6 zCHg?W{bH1Wrwc&{yix($oglH|RTtzEx`{$Hvp|(GLojr>4OJ9_J!rW70M5PZDlc zp409-uE(AR{;G33$6!?pzK<#RvTAmj*X6$)h0L?Dz#fKeb@ZX+*xC|H1e?q>KbYr1-(auA zHP8^)+J@I{hJZts!d<W5Tj=+|T5B{A&+gj-468k{~Bb@TR4#Nd$D9>ZHX=5%<+2$YO*w!|G_4R@}a zcV4KA#9ei&C@Cn*%L5l8{fHUvE^!ZsZ&3iAm+_CB5h&8&UK00qSj_-`BmFuK?kjOW z4Y5FgBJBx<@c@YjYFd^bm{trAJ89TpiHA7+e7Qha3QsgSat@OrXoP@k<^}Wp1sZdt z#G@R{X@KM_%Yp1Qc#Onjbv_X#{+wceX-{~kXDPgB z!%|I=c&bKY1%Z5crOBt6PLnv4<78htBjBH|L4FBaGk~VOKues$hcya*ZvhRDDk+-Z zy)buVPVs!Oi($c_Q{-6^=j#kb4!osR>N+6eLWzSK3ePjtX#4drVE}cIrIM-phK!Tfw!_qem z9{(zH6tGa@+cglJ!xYiB~vT z75GYKm-+Q0N*cUU;#C?f0#KZ}!QxqtsoV`OL^`YsgYZC^1G-1zb$Gpcrl+@6XoJK` zCo^bB)5=O6Mw=ww?9@+LQC=1E`z3xr<9X%=O5lyKys=Q50_Eea5&Wt`jZ69GXdRpRVbc*dO3YO0Bg8+^#@0Pec%myCqf>skQ(_V@9 zxyVJuVB&!sr>LPyiT7)4yQ~nN1}iRsN85C+;8lE3gAGu=gZP}p&m*5>cx8n-f&3A{ zpwk|XNPJZDwMzWHe!e_S`=Z1zIT9E8^mAi3RNOI%k2}bL5^yuth7`iDO4u*d48l(e zY6h=M{Dua3ZhUGF;3p-1%aIj4H;eOoX?ZpJ+Y-N{(OG^lILo!h_rNP!!$hHPP9V<* z?!_AO1BuT#nEnE=`MjVF@6zFqB>q@)g-Qy)&IUf&8u?R+&uTdL&ntp{E1cIkiT|TH z@SL*JqO#%=M>pps{z794XdQm%?J!M$LE^78stsKMcvJgw!!mp$@wX1!5?}rtUkF}R z)5zaT{DUKJ-VCsjs{ZVvgfSjiSku7hf{s)_OZTi-Rr&K!iv_HIlA--LwgKv0EC& zF3?%{^($E#tZz9u(!mQ^(6ltjBZ+h{wZZ#GKxH^!uOu~`Jm%_=Ie18lT=A+X=E7W zis$&9Rz}h!siV=N)wX*RqxEH3Qdg3C8cog!>uQ(}xl(yln*6eUX%7~TL8`fl(^)wIndX|54(c&Si>TT0T(0nZ1m<;|74`3lm8z&2%D zwRUrSd<OKV4VK6M{yueo$v2$HhF?1 z6E#f)3`;rw!SHON9tU)ulO>s=Q>oHGMa|K7>a_y z;;I%#LXs@h9E=h$5S`B*k}T4h8~V{Z4Ok+{QVp4>MUt�~8(FmbPt;xlNMo8s>2nR2-ZZp1_cYC3!@{ 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

=gFgS50_$Kt7B~dr*WpwbZD?lX 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 diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index eaa30027f..3fcc9aea3 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -266,25 +266,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { game.broadcastEvent(event); // test if any prince card left the play - if (currentPlayer.playedByPrince.size() > 0) { - ArrayList playedByPrince = new ArrayList(); - for (int i = 0; i < currentPlayer.playedByPrince.size(); i++) { - playedByPrince.add(currentPlayer.playedByPrince.remove(i)); - } - ArrayList playedCards = new ArrayList(); - for (int i = 0; i < currentPlayer.playedCards.size(); i++) { - playedCards.add(currentPlayer.playedCards.get(i)); - } - for (Card card : playedByPrince) { - if (playedCards.contains(card)) { - playedCards.remove(card); - currentPlayer.playedByPrince.add(card); - } - else { - Util.log("Prince card has left the play:" + card.getName()); - } - } - } + currentPlayer.princeCardLeftThePlay(currentPlayer); } protected void additionalCardActions(Game game, MoveContext context, Player currentPlayer) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 2605a876e..96fbd6840 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -451,6 +451,7 @@ protected void cleanup(MoveContext context) { Collections.sort(playedCards.toArrayList(), new Util.CardTravellerComparator()); while (!playedCards.isEmpty()) { discard(playedCards.remove(0), null, context, false, true); + princeCardLeftThePlay(this); // princed travellers may be exchanged } playedByPrince.clear(); @@ -1020,6 +1021,29 @@ public void gainCardAlreadyInPlay(Card card, Card responsible, MoveContext conte } } + // test if any prince card left the play + public void princeCardLeftThePlay(Player currentPlayer) { + if (currentPlayer.playedByPrince.size() > 0) { + ArrayList playedByPrince = new ArrayList(); + for (int i = 0; i < currentPlayer.playedByPrince.size(); i++) { + playedByPrince.add(currentPlayer.playedByPrince.remove(i)); + } + ArrayList playedCards = new ArrayList(); + for (int i = 0; i < currentPlayer.playedCards.size(); i++) { + playedCards.add(currentPlayer.playedCards.get(i)); + } + for (Card card : playedByPrince) { + if (playedCards.contains(card)) { + playedCards.remove(card); + currentPlayer.playedByPrince.add(card); + } + else { + Util.log("Prince card has left the play:" + card.getName()); + } + } + } + } + public void broadcastEvent(GameEvent event) { game.broadcastEvent(event); } From e8b0d97ebbdd09e7d44bdf54b7b0e6b882e49f75 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 28 Dec 2015 09:26:34 +0100 Subject: [PATCH 004/141] Androminion can handle events given by the App "Jack of all Dominion" --- vdom/src/com/vdom/core/Game.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 99a4987d7..f10e0060c 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1918,6 +1918,12 @@ protected void initCards() { break; } } + for (Card c : Cards.eventsCards) { + if(c.getSafeName().equalsIgnoreCase(s)) { + card = c; + break; + } + } if(card != null && bane) { baneCard = card; } From bf8ba4b836842ef7e520b348a7883fcab0b454e8 Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 28 Dec 2015 14:06:18 -0700 Subject: [PATCH 005/141] Reworking logic to clarify meaning of game.drawToHand() and game.draw() to simplify what card logic needs to care about. game.drawToHand() means "draw" - removes -1 Card token game.draw means() to remove from top of deck as in "reveal" or "look at" top of deck --- vdom/src/com/vdom/core/ActionCardImpl.java | 111 +++++++++---------- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/Game.java | 36 +++--- vdom/src/com/vdom/core/TreasureCardImpl.java | 2 +- 4 files changed, 71 insertions(+), 80 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 3fcc9aea3..e6909f34d 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -987,7 +987,7 @@ private void navigator(Game game, MoveContext context, Player currentPlayer) { private void lookout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { cards.add(card); } @@ -1199,7 +1199,7 @@ private void nativeVillage(Game game, MoveContext context, Player currentPlayer) currentPlayer.hand.add(currentPlayer.nativeVillage.remove(0)); } } else { - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw != null) { currentPlayer.nativeVillage.add(draw); Util.sensitiveDebug(currentPlayer, "Added to Native Village:" + draw.getName(), true); @@ -1213,7 +1213,7 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - Card draw = game.draw(player, true); + Card draw = game.draw(player); if (draw != null) { player.discard(draw, this.controlCard, playerContext); } @@ -1315,7 +1315,7 @@ private void transmute(MoveContext context, Player currentPlayer) { private void apothecary(Game game, MoveContext context, Player currentPlayer) { ArrayList residue = new ArrayList(); for (int i = 1; i <= 4; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); if (card.equals(Cards.copper) || card.equals(Cards.potion)) { @@ -1429,7 +1429,7 @@ private void torturer(Game game, MoveContext context, Player currentPlayer) { private void scout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card == null) { break; } @@ -1863,7 +1863,7 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(player, true); + Card card = game.draw(player); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -1989,7 +1989,6 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { } private void watchTower(Game game, MoveContext context, Player currentPlayer) { - currentPlayer.setMinusOneCardToken(false, context); while (currentPlayer.hand.size() < 6) { if(!game.drawToHand(currentPlayer, this.controlCard)) break; @@ -2001,7 +2000,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(currentPlayer, true)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(currentPlayer)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -2026,7 +2025,7 @@ private void fortuneTeller(Game game, MoveContext context, Player currentPlayer) ArrayList cardsToDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(player, true)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { + while ((draw = game.draw(player)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { player.reveal(draw, this.controlCard, playerContext); cardsToDiscard.add(draw); } @@ -2063,7 +2062,7 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { HashSet cardNames = new HashSet(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 4; i++) { - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw == null) { break; } @@ -2120,7 +2119,7 @@ private void jester(Game game, MoveContext context, Player currentPlayer) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); - Card draw = game.draw(targetPlayer, true); + Card draw = game.draw(targetPlayer); Card virtCard = draw; if (draw == null) @@ -2171,7 +2170,7 @@ private void huntingParty(Game game, MoveContext context, Player currentPlayer) ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, true)) != null && cardNames.contains(draw.getName())) { + while ((draw = game.draw(currentPlayer)) != null && cardNames.contains(draw.getName())) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -2242,7 +2241,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { private void duchess(Game game, MoveContext context) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - Card c = game.draw(targetPlayer, true); + Card c = game.draw(targetPlayer); if(c != null) { MoveContext targetPlayerContext = new MoveContext(context, game, targetPlayer); boolean discard = (targetPlayer).controlPlayer.duchess_shouldDiscardCardFromTopOfDeck(targetPlayerContext, c); @@ -2311,7 +2310,7 @@ private void trader(MoveContext context, Player currentPlayer) { private void cartographer(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { topOfTheDeck.add(card); } @@ -2548,7 +2547,7 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, true); + Card card = game.draw(targetPlayer); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -2764,11 +2763,7 @@ private void tournament(Game game, MoveContext context, Player currentPlayer) { } if (!opponentsRevealedProvince) { - Card draw = game.draw(currentPlayer); - if (draw != null) { - currentPlayer.hand.add(draw); - } - + game.drawToHand(currentPlayer, this); context.addGold++; } } @@ -2949,7 +2944,7 @@ private void saboteur(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw; - while ((draw = game.draw(player, true)) != null) { + while ((draw = game.draw(player)) != null) { if (draw.getCost(context) >= 3) { int value = draw.getCost(context); value -= 2; @@ -3047,7 +3042,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla } MoveContext playerContext = new MoveContext(game, player); - Card card = game.draw(player, true); + Card card = game.draw(player); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -3074,7 +3069,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla ArrayList cardsToPutInHand = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, true)) != null) { + while ((draw = game.draw(currentPlayer)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); if(!(draw instanceof ActionCard)) { @@ -3107,7 +3102,7 @@ private void wishingWell(Game game, MoveContext context, Player currentPlayer) { if (!options.isEmpty()) { Card card = currentPlayer.controlPlayer.wishingWell_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(card, this.controlCard, context); - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -3182,8 +3177,8 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { private void tribute(Game game, MoveContext context, Player currentPlayer) { Card[] revealedCards = new Card[2]; Player nextPlayer = game.getNextPlayer(); - revealedCards[0] = game.draw(nextPlayer, true); - revealedCards[1] = game.draw(nextPlayer, true); + revealedCards[0] = game.draw(nextPlayer); + revealedCards[1] = game.draw(nextPlayer); if (revealedCards[0] != null) { nextPlayer.reveal(revealedCards[0], this.controlCard, new MoveContext(game, nextPlayer)); @@ -3226,7 +3221,7 @@ private void swindler(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - Card draw = game.draw(player, true); + Card draw = game.draw(player); if (draw != null) { player.trash(draw, this.controlCard, playerContext); @@ -3399,7 +3394,7 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { MoveContext targetContext = new MoveContext(game, targetPlayer); ArrayList cards = new ArrayList(); for(int i=0; i < 2; i++) { - Card c = game.draw(targetPlayer, true); + Card c = game.draw(targetPlayer); if(c == null) { break; } @@ -3469,7 +3464,7 @@ private void oasis(MoveContext context, Player currentPlayer) { private void jackOfAllTrades(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); - Card c = game.draw(currentPlayer, true); + Card c = game.draw(currentPlayer); if(c != null) { boolean discard = currentPlayer.controlPlayer.jackOfAllTrades_shouldDiscardCardFromTopOfDeck(context, c); if(discard) { @@ -3478,8 +3473,6 @@ private void jackOfAllTrades(Game game, MoveContext context, Player currentPlaye currentPlayer.putOnTopOfDeck(c); } } - - currentPlayer.setMinusOneCardToken(false, context); while(currentPlayer.hand.size() < 5) { if(!game.drawToHand(currentPlayer, this.controlCard)) { break; @@ -3707,7 +3700,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { ArrayList toOrder = new ArrayList(); while (toOrder.size() < 2) { - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw == null) { break; } @@ -3768,7 +3761,7 @@ private void adventurer(Game game, MoveContext context, Player currentPlayer) { int treasureCardsRevealed = 0; while (treasureCardsRevealed < 2) { - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw == null) { break; } @@ -3789,13 +3782,15 @@ private void adventurer(Game game, MoveContext context, Player currentPlayer) { private void library(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); + // only time a card is "drawn" without being directly drawn to hand + // we need to manually remove the minus one card token currentPlayer.setMinusOneCardToken(false, context); while (currentPlayer.hand.size() < 7) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer); if (draw == null) { break; } - + boolean shouldKeep = true; if (draw instanceof ActionCard) { shouldKeep = currentPlayer.controlPlayer.library_shouldKeepAction(context, (ActionCard) draw); @@ -3869,7 +3864,7 @@ private void pirateShip(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, true); + Card card = game.draw(targetPlayer); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -3963,7 +3958,7 @@ private void chancellor(Game game, MoveContext context, Player currentPlayer) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer, true), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); } } } @@ -4180,7 +4175,7 @@ public void nobleBrigandAttack(MoveContext moveContext, boolean defensible) { List cardsToDiscard = new ArrayList(); for (int j = 0; j < 2; j++) { - Card card = context.game.draw(targetPlayer, true); + Card card = context.game.draw(targetPlayer); if(card == null) { break; } @@ -4273,7 +4268,7 @@ private void sage(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, true)) != null && draw.getCost(context) < 3) { + while ((draw = game.draw(currentPlayer)) != null && draw.getCost(context) < 3) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -4382,7 +4377,7 @@ public void beggar(Player currentPlayer, MoveContext context) { public void catacombs(Game game, Player currentPlayer, MoveContext context) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { topOfTheDeck.add(card); } @@ -4577,7 +4572,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { } private void ironmonger(Game game, Player currentPlayer, MoveContext context) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -4623,7 +4618,7 @@ private void mystic(Game game, MoveContext context, Player currentPlayer) { if (options.size() > 0) { Card toName = currentPlayer.controlPlayer.mystic_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(toName, this.controlCard, context); - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -4649,7 +4644,7 @@ private void scavenger(Game game, MoveContext context, Player currentPlayer) game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer, true), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); } } @@ -4722,7 +4717,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { private void wanderingMinstrel(Player currentPlayer, MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = context.game.draw(currentPlayer, true); + Card card = context.game.draw(currentPlayer); if (card == null) { break; } @@ -4761,7 +4756,7 @@ private void rebuild(Player currentPlayer, MoveContext context) { Card last = null; // search for first Victory card that was not named - while ((last = context.game.draw(currentPlayer, true)) != null) { + while ((last = context.game.draw(currentPlayer)) != null) { if (last instanceof VictoryCard && !last.equals(named)) break; cards.add(last); currentPlayer.reveal(last, this.controlCard, context); @@ -4810,7 +4805,7 @@ private void rogue(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, true); + Card card = game.draw(targetPlayer); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4971,7 +4966,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); Player nextPlayer = game.getNextPlayer(); for (int i = 0; i < 5; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { cards.add(card); currentPlayer.reveal(card, this.controlCard, context); @@ -5159,7 +5154,7 @@ public boolean isTraveller() { private void survivors(MoveContext context, Game game, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { topOfTheDeck.add(card); } @@ -5394,7 +5389,7 @@ private void madman(MoveContext context, Game game, Player currentPlayer) { private void vagrant(MoveContext context, Game game, Player currentPlayer) { - Card c = game.draw(currentPlayer, true); + Card c = game.draw(currentPlayer); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins())) { @@ -5415,7 +5410,7 @@ private void knight(MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = context.game.draw(targetPlayer, true); + Card card = context.game.draw(targetPlayer); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -5695,7 +5690,7 @@ private void advisor(Game game, MoveContext context, Player currentPlayer) for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { @@ -5810,7 +5805,7 @@ private void journeyman(Game game, MoveContext context, Player currentPlayer) { int diffCardsFound = 0; // search for the first 3 cards that were not named - while (diffCardsFound < 3 && (last = context.game.draw(currentPlayer, true)) != null) { + while (diffCardsFound < 3 && (last = context.game.draw(currentPlayer)) != null) { if (!last.equals(named)) { ++diffCardsFound; cardsToKeep.add(last); @@ -5916,7 +5911,7 @@ private void doctor(Game game, MoveContext context, Player currentPlayer) { ArrayList revealedCards = new ArrayList(); for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer, true); + Card card = game.draw(currentPlayer); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -5943,7 +5938,7 @@ public void doctorOverpay(MoveContext context) { for (int i = 0; i < context.overpayAmount; ++i) { - Card card = context.game.draw(context.player, true); + Card card = context.game.draw(context.player); if (card != null) { @@ -5969,7 +5964,7 @@ public void doctorOverpay(MoveContext context) private void herald(Game game, MoveContext context, Player currentPlayer) { - Card draw = game.draw(currentPlayer, true); + Card draw = game.draw(currentPlayer); if (draw != null) { @@ -6147,7 +6142,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) for (Player targetPlayer : playersToAttack) { MoveContext targetContext = new MoveContext(game, targetPlayer); - Card card = game.draw(targetPlayer, true); + Card card = game.draw(targetPlayer); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); int cardCost = card.getCost(context); @@ -6183,7 +6178,7 @@ private void hero(Game game, MoveContext context, Player currentPlayer) private void magpie(Game game, MoveContext context, Player currentPlayer) { - Card c = game.draw(currentPlayer, true); + Card c = game.draw(currentPlayer); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c instanceof TreasureCard) { @@ -6272,7 +6267,7 @@ private void warrior(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); for (int i = 0; i < context.countTravellerCardsInPlayThisTurn(); i++) { - Card draw = game.draw(player, true); + Card draw = game.draw(player); if (draw != null) { player.reveal(draw, this.controlCard, playerContext); if (draw.getCost(context) == 3 || draw.getCost(context) == 4) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 0cc288dba..e50bed230 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -157,7 +157,7 @@ private void save(MoveContext context) { private void scoutingParty(MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = context.game.draw(context.player, true); + Card card = context.game.draw(context.player); if (card != null) { cards.add(card); } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index f10e0060c..dcdf081d0 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1511,12 +1511,17 @@ private boolean checkGameOver() { return false; } - // TODO: all calls should use this but initial turn draws... + // Use drawToHand when "drawing" or "+ X cards" when -1 Card token could be drawn instead boolean drawToHand(Player player, Card responsible) { return drawToHand(player, responsible, true); } boolean drawToHand(Player player, Card responsible, boolean showUI) { + if (player.getMinusOneCardToken()) { + MoveContext context = new MoveContext(this, player); + player.setMinusOneCardToken(false, context); + return false; + } Card card = draw(player); if (card == null) return false; @@ -1530,26 +1535,17 @@ boolean drawToHand(Player player, Card responsible, boolean showUI) { return true; } + // Use draw when removing a card from the top of the deck without "drawing" it (e.g. look at or reveal) Card draw(Player player) { - return draw(player, false); - } - - Card draw(Player player, boolean ignoringMinusOneCardToken) { - if(!ignoringMinusOneCardToken && player.getMinusOneCardToken()) { - MoveContext context = new MoveContext(this, player); - player.setMinusOneCardToken(false, context); - return null; - } else { - if (player.deck.isEmpty()) { - if (player.discard.isEmpty()) { - return null; - } else { - replenishDeck(player); - } - } - - return player.deck.remove(0); - } + if (player.deck.isEmpty()) { + if (player.discard.isEmpty()) { + return null; + } else { + replenishDeck(player); + } + } + + return player.deck.remove(0); } public void replenishDeck(Player player) { diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index cb5b7bb46..5486aa550 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -184,7 +184,7 @@ protected boolean loanVenture(MoveContext context, Player player, Game game, boo GameEvent event = null; while (treasureCardFound == null) { - Card draw = game.draw(player, true); + Card draw = game.draw(player); if (draw == null) { break; } From e8018f76adf9732841a28539d380daf61e3fa41b Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 28 Dec 2015 18:19:50 -0700 Subject: [PATCH 006/141] Implementing -1 Card Token. Correcting Bridge Troll cost. --- vdom/src/com/vdom/core/ActionCardImpl.java | 84 +++++++++----------- vdom/src/com/vdom/core/BasePlayer.java | 8 +- vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/Game.java | 16 +--- vdom/src/com/vdom/core/MoveContext.java | 35 ++++++-- vdom/src/com/vdom/core/TreasureCardImpl.java | 12 +-- 7 files changed, 85 insertions(+), 74 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index e6909f34d..15711d0c3 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -247,7 +247,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { context.actions += addActions; context.buys += addBuys; - context.addGold += addGold; + context.addCoins(addGold); currentPlayer.addVictoryTokens(context, addVictoryTokens); int cardsToDraw = addCards; @@ -1126,7 +1126,7 @@ private void blackMarket(Game game, MoveContext context, Player currentPlayer) { // get one buy from BlackMarkt pile ArrayList canBuy = new ArrayList(); for (int i = 0; i < cards.size(); i++) { - if (context.game.isValidBuy(context, cards.get(i), context.gold)) { + if (context.game.isValidBuy(context, cards.get(i), context.getCoinAvailableForBuy())) { canBuy.add(cards.get(i)); } } @@ -1134,7 +1134,7 @@ private void blackMarket(Game game, MoveContext context, Player currentPlayer) { Card card = currentPlayer.controlPlayer.blackMarket_chooseCard(context, canBuy); if (card != null) { //see playerBuy() - if (context.game.isValidBuy(context, card, context.gold)) { + if (context.game.isValidBuy(context, card, context.getCoinAvailableForBuy())) { GameEvent statusEvent = new GameEvent(GameEvent.Type.Status, (MoveContext) context); context.game.broadcastEvent(statusEvent); @@ -1184,12 +1184,6 @@ private void blackMarket(Game game, MoveContext context, Player currentPlayer) { } } - // correct gold and potion count - context.addGold = context.gold; - context.gold = 0; - context.addPotions = context.potions; - context.potions = 0; - context.blackMarketBuyPhase = false; } @@ -1603,7 +1597,7 @@ private void salvager(MoveContext context, Player currentPlayer) { card = currentPlayer.hand.get(0); } - context.addGold += card.getCost(context); + context.addCoins(card.getCost(context)); currentPlayer.hand.remove(card); currentPlayer.trash(card, this.controlCard, context); } @@ -1641,7 +1635,7 @@ private void city(Game game, MoveContext context, Player currentPlayer) { } if (game.emptyPiles() > 1) { context.buys++; - context.addGold++; + context.addCoins(1); } } @@ -1932,7 +1926,7 @@ private void tradeRoute(Game game, MoveContext context, Player currentPlayer) { currentPlayer.trash(card, this.controlCard, context); } - context.addGold += game.tradeRouteValue; + context.addCoins(game.tradeRouteValue); } private void vault(Game game, MoveContext context, Player currentPlayer) { @@ -1950,7 +1944,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Vault discard error, trying to discard cards not in hand, ignoring extra."); } - context.addGold += numberOfCardsDiscarded; + context.addCoins(numberOfCardsDiscarded); } for (Player player : game.getPlayersInTurnOrder()) { @@ -2075,7 +2069,7 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { currentPlayer.discard(c, this.controlCard, context); } - context.addGold += cardNames.size(); + context.addCoins(cardNames.size()); } private void horseTradersDungeon(MoveContext context, Player currentPlayer) { @@ -2221,7 +2215,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { game.drawToHand(currentPlayer, this.controlCard); } } else if (option == TrustySteedOption.AddGold) { - context.addGold += 2; + context.addCoins(2); } else if (option == TrustySteedOption.GainSilvers) { for (int i = 0; i < 4; i++) { if(currentPlayer.gainNewCard(Cards.silver, this.controlCard, context) == null) { @@ -2280,7 +2274,7 @@ private void spiceMerchant(Game game, MoveContext context, Player currentPlayer) context.actions += 1; } else { - context.addGold += 2; + context.addCoins(2); context.buys += 1; } } @@ -2487,7 +2481,7 @@ private void steward(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Steward option error, ignoring."); } else { if (option == Player.StewardOption.AddGold) { - context.addGold += 2; + context.addCoins(2); } else if (option == Player.StewardOption.AddCards) { game.drawToHand(currentPlayer, this.controlCard); game.drawToHand(currentPlayer, this.controlCard); @@ -2764,7 +2758,7 @@ private void tournament(Game game, MoveContext context, Player currentPlayer) { if (!opponentsRevealedProvince) { game.drawToHand(currentPlayer, this); - context.addGold++; + context.addCoins(1); } } @@ -2870,7 +2864,7 @@ private void masquerade(Game game, MoveContext context, Player currentPlayer) { private void miningVillage(MoveContext context, Player currentPlayer) { if (!this.controlCard.movedToNextTurnPile) { if (currentPlayer.controlPlayer.miningVillage_shouldTrashMiningVillage(context)) { - context.addGold += 2; + context.addCoins(2); this.controlCard.movedToNextTurnPile = true; currentPlayer.trash(this.controlCard, null, context); currentPlayer.playedCards.remove(currentPlayer.playedCards.lastIndexOf(this.controlCard)); @@ -2897,7 +2891,7 @@ private void minion(Game game, MoveContext context, Player currentPlayer) { } if (option == Player.MinionOption.AddGold) { - context.addGold += 2; + context.addCoins(2); } else if (option == Player.MinionOption.RolloverCards) { for (Player player : playersToAttack) { if (player == currentPlayer || player.hand.size() >= 5) { @@ -2928,7 +2922,7 @@ private void pawn(Game game, MoveContext context, Player currentPlayer) { } else if (option == Player.PawnOption.AddCard) { game.drawToHand(currentPlayer, this.controlCard); } else if (option == Player.PawnOption.AddGold) { - context.addGold++; + context.addCoins(1); } } } @@ -3011,7 +3005,7 @@ private void baron(MoveContext context, Player currentPlayer) { Card card = currentPlayer.hand.get(Cards.estate); currentPlayer.hand.remove(Cards.estate); currentPlayer.discard(card, this.controlCard, context); - context.addGold += 4; + context.addCoins(4); } else { currentPlayer.gainNewCard(Cards.estate, this.controlCard, context); } @@ -3150,7 +3144,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { context.actions++; } if (card instanceof TreasureCard) { - context.addGold++; + context.addCoins(1); } if (card instanceof VictoryCard) { game.drawToHand(currentPlayer, this.controlCard); @@ -3201,7 +3195,7 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { context.actions += 2; } if (card instanceof TreasureCard) { - context.addGold += 2; + context.addCoins(2); } if (card instanceof VictoryCard) { game.drawToHand(currentPlayer, this.controlCard); @@ -3644,7 +3638,7 @@ private void secretChamber(MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Secret chamber discard error, trying to discard cards not in hand, ignoring extra."); } - context.addGold += numberOfCardsDiscarded; + context.addCoins(numberOfCardsDiscarded); } } @@ -3968,7 +3962,7 @@ private void moneyLender(MoveContext context, Player currentPlayer) { Card card = currentPlayer.hand.get(i); if (card.equals(Cards.copper)) { Card thisCard = currentPlayer.hand.remove(i); - context.addGold += 3; + context.addCoins(3); currentPlayer.trash(thisCard, this.controlCard, context); break; } @@ -4059,7 +4053,7 @@ protected void increasePirateShipTreasure(Player player) { } protected void takePirateShipTreasure(MoveContext context) { - ((MoveContext) context).addGold += (context.getPlayer()).pirateShipTreasure; + context.addCoins(context.getPlayer().pirateShipTreasure); } // TODO better way to do, possible security hole @@ -4253,7 +4247,7 @@ private void poorHouse(MoveContext context, Player currentPlayer) { treasures++; } } - context.addGold = Math.max(0, context.addGold-treasures); + context.addCoins(-treasures); } private void sage(Game game, MoveContext context, Player currentPlayer) { @@ -4468,7 +4462,7 @@ private void count(Player currentPlayer, MoveContext context) { } else { switch (option2) { case Coins: - context.addGold += 3; + context.addCoins(3); break; case TrashHand: if (currentPlayer.hand.size() > 0) { @@ -4524,7 +4518,7 @@ private void forager(Game game, Player currentPlayer, MoveContext context) { cardNames.add(card.getName()); } } - context.addGold += cardNames.size(); + context.addCoins(cardNames.size()); } private void graverobber(Game game, Player currentPlayer, MoveContext context) { @@ -4586,7 +4580,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { context.actions += 1; } if (card instanceof TreasureCard) { - context.addGold++; + context.addCoins(1); } if (card instanceof VictoryCard) { game.drawToHand(currentPlayer, this.controlCard); @@ -4709,7 +4703,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { while (numberOfCards > 0) { numberOfCards--; - context.addGold++; + context.addCoins(1); } } } @@ -5285,7 +5279,7 @@ private void mercenary(MoveContext context, Game game, Player currentPlayer) game.drawToHand(currentPlayer, this.controlCard); game.drawToHand(currentPlayer, this.controlCard); - context.addGold += 2; + context.addCoins(2); for (Player player : game.getPlayersInTurnOrder()) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { @@ -6033,7 +6027,7 @@ private void amulet(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Amulet option error, ignoring."); } else { if (option == Player.AmuletOption.AddGold) { - context.addGold += 1; + context.addCoins(1); } else if (option == Player.AmuletOption.GainSilver) { currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); } else if (option == Player.AmuletOption.TrashCard) { @@ -6137,7 +6131,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) } } if(currentPlayer.flipJourneyToken(context)) { - context.addGold += 5; + context.addCoins(5); for (Player targetPlayer : playersToAttack) { MoveContext targetContext = new MoveContext(game, targetPlayer); @@ -6157,7 +6151,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) } } else { - context.addGold += 1; + context.addCoins(1); } } @@ -6195,7 +6189,7 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) private void miser(Game game, MoveContext context, Player currentPlayer) { boolean takeTreasure = currentPlayer.controlPlayer.miser_shouldTakeTreasure(context); if (takeTreasure) { - context.addGold += currentPlayer.getMiserTreasure(); + context.addCoins(currentPlayer.getMiserTreasure()); } else { for (int i = 0; i < currentPlayer.hand.size(); i++) { @@ -6212,15 +6206,14 @@ private void miser(Game game, MoveContext context, Player currentPlayer) { } } - private void ranger(Game game, MoveContext context, Player currentPlayer) - { + private void ranger(Game game, MoveContext context, Player currentPlayer) { if(currentPlayer.flipJourneyToken(context)) { drawToHand(game, currentPlayer, this.controlCard, 5); } } private void soldier(Game game, MoveContext context, Player currentPlayer) { - context.addGold += context.countAttackCardsInPlayThisTurn() -1; //without this soldier + context.addCoins(context.countAttackCardsInPlayThisTurn() - 1); //without this soldier for (Player player : context.game.getPlayersInTurnOrder()) { if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this.controlCard)) { player.attacked(this.controlCard, context); @@ -6242,14 +6235,15 @@ private void soldier(Game game, MoveContext context, Player currentPlayer) { } private void storyteller(Game game, MoveContext context, Player currentPlayer) { - // play treasures + // play up to 3 treasures context.game.playTreasures(currentPlayer, context, 3); - while (context.gold > 0) { - context.gold--; - game.drawToHand(currentPlayer, this.controlCard); + int coins = context.getCoins(); + context.spendCoins(coins); + + for (int i = 0; i < coins; i++) { + game.drawToHand(currentPlayer, this.controlCard); } - context.gold = 0; } private void treasureHunter(Game game, MoveContext context, Player currentPlayer) { diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index faa53ea82..54cbdce9c 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -1140,19 +1140,19 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis @Override public Card blackMarket_chooseCard(MoveContext context, ArrayList cardList) { - if(context.gold == 8 && cardList.contains(Cards.prince) && turnCount < midGame && context.cardInGame(Cards.colony) && getMyCardCount(Cards.prince) < 2) { + if(context.getCoins() == 8 && cardList.contains(Cards.prince) && turnCount < midGame && context.cardInGame(Cards.colony) && getMyCardCount(Cards.prince) < 2) { ArrayList allCards = new ArrayList(getAllCards()); if (prince_cardCandidates(context, allCards, false).length >= 2 + 2*getMyCardCount(Cards.prince)) return Cards.prince; } - if (context.gold >= 8) { + if (context.getCoins() >= 8) { return null; } ArrayList keyList = new ArrayList(); final Card[] KEY_CARDS = new Card[] { Cards.scryingPool, Cards.masquerade, Cards.swindler, Cards.familiar, Cards.militia, Cards.seaHag, Cards.tournament, Cards.youngWitch, Cards.golem, Cards.cultist, Cards.mountebank, Cards.torturer, Cards.minion, Cards.governor, Cards.illGottenGains, Cards.saboteur, Cards.ghostShip, Cards.wharf, Cards.witch, Cards.goons, Cards.grandMarket }; for (Card card : KEY_CARDS) { - if (cardList.contains(card) && (context.gold - card.getCost(context, false) <= 2 || context.potions > 0 && card.costPotion())) { + if (cardList.contains(card) && (context.getCoins() - card.getCost(context, false) <= 2 || context.potions > 0 && card.costPotion())) { keyList.add(card); } } @@ -1162,7 +1162,7 @@ public Card blackMarket_chooseCard(MoveContext context, ArrayList cardList keyList.clear(); for (Card card : cardList) { - if (context.gold - card.getCost(context, false) <= 1) { + if (context.getCoins() - card.getCost(context, false) <= 1) { if ( !card.equals(Cards.treasureMap) && !card.equals(Cards.rats) /*AIs don't play rats*/) { keyList.add(card); diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index d29f6156e..6b86139df 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -701,7 +701,7 @@ public enum Type { // Adventures actionCardsAdventures.add(amulet = new ActionDurationCardImpl.Builder(Cards.Type.Amulet, 3).description("Now and at the start of your next turn, choose one: +1 Coin; or trash a card from your hand; or gain a Silver.").expansion("Adventures").build()); actionCardsAdventures.add(artificer = new ActionCardImpl.Builder(Cards.Type.Artificer, 5).addCards(1).addActions(1).addGold(1).description("Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck.").expansion("Adventures").build()); - actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 3).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is on play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); + actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 5).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is on play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 2).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index e50bed230..9757e79da 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -121,7 +121,7 @@ private void bonfire(MoveContext context) { protected void borrow(MoveContext context) { if (!context.player.getMinusOneCardToken()) { context.player.setMinusOneCardToken(true, context); - context.addGold += 1; + context.addCoins(1); } context.cantBuy.add(this); //once per turn } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index dcdf081d0..ccfc9087d 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -366,11 +366,6 @@ public int cardsInLowestPiles (int numPiles) { protected void playTreasures(Player player, MoveContext context, int maxCards) { // storyteller sets maxCards != -1 - // Set the turn gold to the correct amount - context.gold = context.addGold; - context.addGold = 0; - context.potions = context.addPotions; - context.addPotions = 0; if (!context.blackMarketBuyPhase && maxCards == -1) { context.buyPhase = true; } @@ -405,7 +400,7 @@ protected void playGuildsTokens(Player player, MoveContext context) if (numTokensToSpend > 0 && numTokensToSpend <= coinTokenTotal) { player.spendGuildsCoinTokens(numTokensToSpend); - context.addGold += numTokensToSpend; + context.addCoins(numTokensToSpend); if(numTokensToSpend > 0) { GameEvent event = new GameEvent(GameEvent.Type.GuildsTokenSpend, context); @@ -596,10 +591,8 @@ protected boolean playerEndTurn(Player player, MoveContext context) { context.actionsPlayedSoFar = 0; context.actions = 1; context.buys = 1; - context.addGold = 0; context.coppersmithsPlayed = 0; - context.gold = context.getCoinAvailableForBuy(); - + GameEvent event = new GameEvent(GameEvent.Type.NewHand, context); broadcastEvent(event); event = null; @@ -827,14 +820,13 @@ protected void playerBeginTurn(Player player, MoveContext context) { broadcastEvent(event); context.actions += thisCard.getAddActionsNextTurn(); - context.addGold += thisCard.getAddGoldNextTurn(); + context.addCoins(thisCard.getAddGoldNextTurn()); context.buys += thisCard.getAddBuysNextTurn(); int addCardsNextTurn = thisCard.getAddCardsNextTurn(); /* addCardsNextTurn are displayed like addCards but sometimes the text differs */ if (thisCard.getType() == Cards.Type.Tactician) { context.actions += 1; - context.addGold += 0; context.buys += 1; addCardsNextTurn = 5; } @@ -1386,7 +1378,7 @@ Card playBuy(MoveContext context, Card buy) { } } - context.gold -= (buy.getCost(context) + context.overpayAmount); + context.spendCoins(buy.getCost(context) + context.overpayAmount); if (buy.costPotion()) { context.potions--; diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index dea8df4ae..23a483794 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -16,10 +16,8 @@ public class MoveContext { public int actions = 1; public int buys = 1; - public int addGold = 0; - public int addPotions = 0; - public int gold; + private int coins = 0; public int potions; public int actionsPlayedSoFar = 0; public int treasuresPlayedSoFar = 0; /* Doesn't work because of Spoils or Mint */ @@ -69,7 +67,7 @@ public MoveContext(Game game, Player player) { public MoveContext(MoveContext context, Game game, Player player) { this.actions = context.actions; this.buys = context.buys; - this.addGold = context.addGold; + this.coins = context.coins; this.game = game; this.player = player; } @@ -301,9 +299,36 @@ public int getActionsLeft() { public int getBuysLeft() { return buys; } + + public int getCoins() { + return coins; + } public int getCoinAvailableForBuy() { - return gold + addGold; + return getCoins(); + } + + public void addCoins(int coinsToAdd) { + addCoins(coinsToAdd, null); + } + + public void addCoins(int coinsToAdd, Card responsible) { + if (coinsToAdd == 0) + return; + if (coinsToAdd > 0) { + if (getPlayer().getMinusOneCoinToken()) { + --coinsToAdd; + getPlayer().setMinusOneCoinToken(false, this); + } + } + + coins += coinsToAdd; + if (coins < 0) + coins = 0; + } + + public void spendCoins(int coinsToSpend) { + coins -= coinsToSpend; } public int getCoinForStatus() { diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 5486aa550..5e619fabf 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -105,7 +105,7 @@ public boolean playTreasure(MoveContext context, boolean isClone) { context.treasuresPlayedSoFar++; } - context.gold += getValue(); + context.addCoins(getValue()); if (providePotion()) { context.potions++; @@ -115,13 +115,13 @@ public boolean playTreasure(MoveContext context, boolean isClone) { if (equals(Cards.foolsGold)) { foolsGold(context); } else if (equals(Cards.philosophersStone)) { - context.gold += (player.getDeckSize() + player.getDiscardSize()) / 5; + context.addCoins((player.getDeckSize() + player.getDiscardSize()) / 5); } else if (equals(Cards.diadem)) { - context.gold += context.getActionsLeft(); + context.addCoins(context.getActionsLeft()); } else if (equals(Cards.copper)) { - context.gold += context.coppersmithsPlayed; + context.addCoins(context.coppersmithsPlayed); } else if (equals(Cards.bank)) { - context.gold += treasuresInPlay(player.playedCards); + context.addCoins(treasuresInPlay(player.playedCards)); } else if (equals(Cards.contraband)) { reevaluateTreasures = contraband(context, game, reevaluateTreasures); } else if (equals(Cards.loan) || equals(Cards.venture)) { @@ -162,7 +162,7 @@ protected int treasuresInPlay(CardList playedCards) { protected void foolsGold(MoveContext context) { context.foolsGoldPlayed++; if (context.foolsGoldPlayed > 1) { - context.gold += 3; + context.addCoins(3); } } From e5d75c2831b0ccd3cf5a27d14441817eb22cf7af Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 28 Dec 2015 18:27:03 -0700 Subject: [PATCH 007/141] Implmenting -1 Coin Token. Correcting Bridge Troll attack effect order. --- vdom/src/com/vdom/core/ActionCardImpl.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 15711d0c3..05186cdbe 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -6081,19 +6081,14 @@ private void artificer(Game game, MoveContext context, Player currentPlayer) { } private void bridgeTroll(Game game, MoveContext context, Player currentPlayer) - { - ArrayList playersToAttack = new ArrayList(); + { for (Player targetPlayer : game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { - playersToAttack.add(targetPlayer); + MoveContext targetContext = new MoveContext(context.game, targetPlayer); targetPlayer.attacked(this.controlCard, context); + targetPlayer.setMinusOneCoinToken(true, targetContext); } } - - for (Player targetPlayer : playersToAttack) { - MoveContext targetContext = new MoveContext(context.game, targetPlayer); - targetPlayer.setMinusOneCoinToken(true, targetContext); - } } private void disciple(Game game, MoveContext context, Player currentPlayer) From 183579a82de1969778984d1e9db532935d10a40e Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 28 Dec 2015 23:55:21 -0700 Subject: [PATCH 008/141] Modified Event pile view in UI to separate location below Supply. Modified Event and Reserve colors in UI. --- androminion/res/layout/view_supply.xml | 14 ++++++++++++++ androminion/res/values/colors.xml | 4 ++-- .../src/com/mehtank/androminion/ui/CardView.java | 11 +++++++++-- .../com/mehtank/androminion/ui/GameTable.java | 16 +++++++++++++--- vdom/src/com/vdom/comms/MyCard.java | 4 +++- vdom/src/com/vdom/core/Game.java | 1 - vdom/src/com/vdom/core/MoveContext.java | 1 - vdom/src/com/vdom/core/RemotePlayer.java | 1 + 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/androminion/res/layout/view_supply.xml b/androminion/res/layout/view_supply.xml index 3c8d14e2f..63ded388d 100644 --- a/androminion/res/layout/view_supply.xml +++ b/androminion/res/layout/view_supply.xml @@ -44,6 +44,20 @@ android:numColumns="4" android:stretchMode="columnWidth" android:verticalSpacing="@dimen/margin_cards" /> + + #33CCFF #9400D3 #806F49 - #E6DEC8 - #E0D53A + #B0AFA7 + #E6DEC8 \ No newline at end of file diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index 721385c8d..aab5d5e82 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -53,6 +53,7 @@ public class CardView extends FrameLayout implements OnLongClickListener, Checka private String viewstyle; private boolean autodownload; private Context top; + private boolean hideCountLeft; CardGroup parent; private CardState state; @@ -156,6 +157,11 @@ public void setCard(MyCard c) { } else { cost.setVisibility(VISIBLE); } + + if (c.isEvent){ + hideCountLeft = true; + countLeft.setVisibility(GONE); + } // TODO: Merge this border with the color setting below, then get rid of cardBox. if (viewstyle.equals("viewstyle-simple")) { @@ -323,7 +329,8 @@ public void setChecked(boolean arg0, int order, String indicator) { public void setCountLeft(int s) { countLeft.setText(" " + s + " "); - countLeft.setVisibility(VISIBLE); + countLeft.setVisibility(hideCountLeft ? GONE : VISIBLE); + if (s == 0) shade(true); else @@ -364,7 +371,7 @@ public void setState(CardState s) { } void setOnTable(boolean onTable) { - countLeft.setVisibility(onTable ? VISIBLE : GONE); + countLeft.setVisibility(onTable && !hideCountLeft ? VISIBLE : GONE); if (cardDesc != null) cardDesc.setVisibility((onTable && "viewstyle-descriptive".equals(viewstyle)) ? VISIBLE : GONE); if (onTable && "viewstyle-classic".equals(viewstyle)) { diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 43e14c0cc..2718de326 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -56,8 +56,8 @@ public PlayerAdapter getPlayerAdapter() { TextView playedHeader; LinearLayout myCards; - GridView moneyPileGV, vpPileGV, supplyPileGV, prizePileGV, nonSupplyPileGV; - CardGroup moneyPile, vpPile, supplyPile, prizePile, nonSupplyPile; + GridView moneyPileGV, vpPileGV, supplyPileGV, prizePileGV, nonSupplyPileGV, eventPileGV; + CardGroup moneyPile, vpPile, supplyPile, prizePile, nonSupplyPile, eventPile; LinearLayout tr; LinearLayout gameOver; @@ -146,6 +146,12 @@ private void initTable() { prizePileGV.setAdapter(prizePile); prizePileGV.setOnItemClickListener(this); prizePileGV.setOnItemLongClickListener(this); + + eventPile = new CardGroup(top, true); + eventPileGV = (GridView) findViewById(R.id.eventPileGV); + eventPileGV.setAdapter(eventPile); + eventPileGV.setOnItemClickListener(this); + eventPileGV.setOnItemLongClickListener(this); } /** @@ -309,6 +315,7 @@ public void newGame(MyCard[] cards, String[] players) { vpPile.clear(); supplyPile.clear(); prizePile.clear(); + eventPile.clear(); nonSupplyPile.clear(); hand.clear(); played.clear(); @@ -426,6 +433,8 @@ else if (c.pile == MyCard.PRIZEPILE) prizePile.addCard(c); else if (c.pile == MyCard.NON_SUPPLY_PILE) nonSupplyPile.addCard(c); + else if (c.pile == MyCard.EVENTPILE) + eventPile.addCard(c); } /** @@ -464,7 +473,8 @@ else if (sco.fromTable) { } else { if ((parent != vpPile) && (parent != moneyPile) - && (parent != supplyPile)) return false; + && (parent != supplyPile) + && (parent != eventPile)) return false; } } else if (sco.fromPrizes) { if (parent != prizePile) return false; diff --git a/vdom/src/com/vdom/comms/MyCard.java b/vdom/src/com/vdom/comms/MyCard.java index 8e5f80aa3..fe3bb66a3 100644 --- a/vdom/src/com/vdom/comms/MyCard.java +++ b/vdom/src/com/vdom/comms/MyCard.java @@ -7,8 +7,9 @@ import com.vdom.core.Util.MultilevelComparator; public class MyCard implements Serializable { - private static final long serialVersionUID = -1367468781663470597L; + private static final long serialVersionUID = 4918045082221992494L; + public int id; public String name; public String expansion; @@ -52,6 +53,7 @@ public class MyCard implements Serializable { public static final int RUINS_PILES = 7; public static final int KNIGHTS_PILES = 8; public static final int BLACKMARKET_PILE = 9; + public static final int EVENTPILE = 10; public int pile; diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index ccfc9087d..d6a4d67c9 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -660,7 +660,6 @@ protected void playerAction(Player player, MoveContext context) { protected void playerBuy(Player player, MoveContext context) { Card buy = null; - context.goldAvailable = context.getCoinAvailableForBuy(); do { try { buy = player.controlPlayer.doBuy(context); diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index 23a483794..fcbe1aa03 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -21,7 +21,6 @@ public class MoveContext { public int potions; public int actionsPlayedSoFar = 0; public int treasuresPlayedSoFar = 0; /* Doesn't work because of Spoils or Mint */ - public int goldAvailable; public int coppersmithsPlayed = 0; public int schemesPlayed = 0; diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 8ebaffba2..674337798 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -221,6 +221,7 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla if (c instanceof EventCard) { EventCard ac = (EventCard) c; card.isEvent = true; + card.pile = MyCard.EVENTPILE; } return card; From b03e2641b7b0a3bbcd22935d5df73b9d970d6a97 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 02:10:14 -0700 Subject: [PATCH 009/141] Implementing Raze (Adventures). Showing Events in appropriate number of columns to minimize number of rows. Adding Game events for setting aside cards with Haven and Gear. Checking Haven / Gear to avoid showing player option when unecessary. Handling Player error cases for Gear. --- androminion/res/values-de/strings-server.xml | 5 +- androminion/res/values/strings-server.xml | 18 +++-- .../com/mehtank/androminion/ui/GameTable.java | 14 ++++ .../com/mehtank/androminion/ui/Strings.java | 16 ++++- vdom/src/com/vdom/api/GameEvent.java | 2 + vdom/src/com/vdom/core/ActionCardImpl.java | 67 ++++++++++++++++++- vdom/src/com/vdom/core/BasePlayer.java | 67 +++++++++++++++++++ vdom/src/com/vdom/core/CardList.java | 5 ++ vdom/src/com/vdom/core/Cards.java | 4 +- vdom/src/com/vdom/core/IndirectPlayer.java | 26 +++++++ vdom/src/com/vdom/core/Player.java | 18 +++-- vdom/src/com/vdom/core/QuickPlayPlayer.java | 15 +++++ vdom/src/com/vdom/core/RemotePlayer.java | 7 +- vdom/src/com/vdom/core/Util.java | 34 ++++++++++ 14 files changed, 270 insertions(+), 28 deletions(-) diff --git a/androminion/res/values-de/strings-server.xml b/androminion/res/values-de/strings-server.xml index d381057ff..2a522608f 100644 --- a/androminion/res/values-de/strings-server.xml +++ b/androminion/res/values-de/strings-server.xml @@ -144,6 +144,9 @@ Spieldauer: Zugende Ersetze + + Entsorge eine Handkarte + Nimm dir ein Silber [Geheimkammer]: Lege oben auf den Nachziehstapel: Wähle [Geheimkammer]: Lege ab: Wähle @@ -224,8 +227,6 @@ Entsorge zwei Karten aus deiner Hand +(1) Geld - Entsorge eine Handkarte - Nimm dir ein Silber +2 Aktionen +2 Käufe diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 37b1d5951..f462d2961 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -133,6 +133,8 @@ Card removed from hand Card put on tavern mat Card set aside (prince) + Card set aside (Haven) + Card set aside (Gear) Card set aside on island mat Deck put into discard pile Journey token turned face up @@ -150,6 +152,10 @@ End turn Replace + Trash card from hand + Gain a Silver + Trash this card + put back on deck [Secret Chamber] [Secret Chamber] Select cards to discard @@ -167,6 +173,8 @@ Select action card to put back on deck + Select card to put in hand + Select treasure card to put back on deck Select treasure to steal @@ -230,9 +238,7 @@ Trash two cards from your hand +(1) Coin - Trash a card from your hand - Gain a Silver - + +2 Actions +2 Buys Gain a Silver @@ -296,7 +302,7 @@ Attack Take +(%1$s) Coins Put a Copper onto Tavern mat - + Top of deck replace your sabotaged card @@ -305,9 +311,9 @@ put on top of your deck - put aside + put aside [Haven] - put aside + put aside [Gear] put on island mat diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 2718de326..452be0b92 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -362,6 +362,12 @@ public void newGame(MyCard[] cards, String[] players) { potionInPlay = true; break; } + + int numEvents = 0; + //count events + for (MyCard c : cards) + if(c.isEvent) + numEvents++; // adjust size of pile table if(potionInPlay && platInPlay) @@ -373,6 +379,14 @@ public void newGame(MyCard[] cards, String[] players) { vpPileGV.setNumColumns(4); else vpPileGV.setNumColumns(5); + + if (numEvents <= 3 || numEvents == 6) { + eventPileGV.setNumColumns(3); + } else if (numEvents == 4 || numEvents == 7 || numEvents == 8 || numEvents == 11 || numEvents == 12) { + eventPileGV.setNumColumns(4); + } else { + eventPileGV.setNumColumns(5); + } short nonSupplyCardsInPlay = 0; diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 899ab2201..8650f97a0 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -104,7 +104,7 @@ public static String getCardDescription(Card c) { } public static String getCardExpansion(Card c) { - if (c.getExpansion().isEmpty()) { + if (c.getExpansion() == "") { // Victory cards (e.g. "Duchy") don't have a single expansion; // they're both in Base and Intrigue. return ""; @@ -259,6 +259,10 @@ public static String getStatusText(Event event, Object[] extras) { statusText += getString(R.string.PlayingDurationAction); } else if (event.gameEventType == GameEvent.Type.CardSetAside) { statusText += getString(R.string.CardSetAside); + } else if (event.gameEventType == GameEvent.Type.CardSetAsideHaven) { + statusText += getString(R.string.CardSetAsideHaven); + } else if (event.gameEventType == GameEvent.Type.CardSetAsideGear) { + statusText += getString(R.string.CardSetAsideGear); } else if (event.gameEventType == GameEvent.Type.CardSetAsideOnTavernMat) { statusText += getString(R.string.CardSetAsideOnTavernMat); } else if (event.gameEventType == GameEvent.Type.CardSetAsideOnIslandMat) { @@ -574,6 +578,8 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { return getActionString(ActionType.OPPONENTDISCARD, card, (String) extras[0]); } else if (cardName.equals(getCardName(Cards.pirateShip))) { return getString(R.string.treasure_to_trash); + } else if (cardName.equals(getCardName(Cards.raze))) { + return getString(R.string.raze_query); } else if (cardName.equals(getCardName(Cards.scheme))) { return getString(R.string.scheme_query); } else if (cardName.equals(getCardName(Cards.smugglers))) { @@ -626,9 +632,9 @@ public static String getOptionText(Object option, Object[] extras) { if (option == AmuletOption.AddGold) { return getString(R.string.amulet_option_one); } else if (option == AmuletOption.TrashCard) { - return getString(R.string.amulet_option_two); + return getString(R.string.trash_card_from_hand); } else if (option == AmuletOption.GainSilver) { - return getString(R.string.amulet_option_three); + return getString(R.string.gain_silver); } } else if (option instanceof NoblesOption) { if (option == NoblesOption.AddCards) { @@ -875,6 +881,9 @@ public static String[] getBooleanStrings(Card cardResponsible, Object[] extras) strings[0] = format(R.string.card_revealed, extras[0], cardNames); strings[1] = getString(R.string.top_of_deck); strings[2] = getString(R.string.discard); + } else if (cardName.equals(getCardName(Cards.raze))) { + strings[1] = getString(R.string.trash_this); + strings[2] = getString(R.string.trash_card_from_hand); } else if (cardName.equals(getCardName(Cards.royalSeal))) { strings[0] = getCardRevealedHeader(extras); strings[1] = getString(R.string.top_of_deck); @@ -1154,6 +1163,7 @@ private static void initActionStrings() { getCardName(Cards.artificer), getCardName(Cards.bonfire), getCardName(Cards.dungeon), + getCardName(Cards.raze), getCardName(Cards.storyteller), getCardName(Cards.treasureTrove) )); diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index 02666bac1..38a9f73e7 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -40,6 +40,8 @@ public enum Type { CardAddedToHand, // A new card has been added to a player's hand CardRemovedFromHand, // A card has been removed from a player's hand CardSetAside, // A card was set aside (prince) + CardSetAsideGear, // A card was set aside (gear) + CardSetAsideHaven, // A card was set aside (haven) CardSetAsideOnTavernMat, // A card was set aside on tavern mat CardSetAsideOnIslandMat, // A card was set aside on island mat DeckPutIntoDiscardPile, // Deck put into discard pile diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 05186cdbe..8c1d75442 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -786,6 +786,9 @@ protected void additionalCardActions(Game game, MoveContext context, Player curr case Ranger: ranger(game, context, currentPlayer); break; + case Raze: + raze(game, context, currentPlayer); + break; case Soldier: soldier(game, context, currentPlayer); break; @@ -3823,7 +3826,7 @@ private void chapel(MoveContext context, Player currentPlayer) { } private void haven(MoveContext context, Player currentPlayer) { - Card card = currentPlayer.controlPlayer.haven_cardToSetAside(context); + Card card = currentPlayer.getHand().size() == 0 ? null : currentPlayer.controlPlayer.haven_cardToSetAside(context); if ((card == null && hand(currentPlayer).size() > 0) || (card != null && !hand(currentPlayer).contains(card))) { Util.playerError(currentPlayer, "Haven set aside card error, setting aside the first card in hand."); card = hand(currentPlayer).get(0); @@ -3832,6 +3835,9 @@ private void haven(MoveContext context, Player currentPlayer) { if (card != null) { hand(currentPlayer).remove(card); haven(currentPlayer).add(card); + GameEvent event = new GameEvent(GameEvent.Type.CardSetAsideHaven, (MoveContext) context); + event.card = card; + context.game.broadcastEvent(event); } else if (this.controlCard.cloneCount == 1) { currentPlayer.nextTurnCards.remove(this.controlCard); currentPlayer.playedCards.add(this.controlCard); @@ -6100,13 +6106,24 @@ private void disciple(Game game, MoveContext context, Player currentPlayer) private void gear(MoveContext context, Player currentPlayer) { boolean cardSetAside = false; - Card[] cards = currentPlayer.controlPlayer.gear_cardsToSetAside(context); + Card[] cards = currentPlayer.getHand().size() == 0 ? null : currentPlayer.controlPlayer.gear_cardsToSetAside(context); + if (cards.length > 2) { + Util.playerError(currentPlayer, "Gear: Tried to set aside too many cards. Setting aside zero."); + cards = null; + } + if (!Util.areCardsInHand(cards, context)) { + Util.playerError(currentPlayer, "Gear: Tried to set aside cards not in hand. Setting aside zero."); + cards = null; + } if (cards != null) { for (Card card : cards) { if (card != null) { cardSetAside = true; hand(currentPlayer).remove(card); haven(currentPlayer).add(card); + GameEvent event = new GameEvent(GameEvent.Type.CardSetAsideGear, (MoveContext) context); + event.card = card; + context.game.broadcastEvent(event); } } } @@ -6206,6 +6223,52 @@ private void ranger(Game game, MoveContext context, Player currentPlayer) { drawToHand(game, currentPlayer, this.controlCard, 5); } } + + private void raze(Game game, MoveContext context, Player currentPlayer) { + int trashCost = 0; + if (currentPlayer.controlPlayer.raze_shouldTrashRazePlayed(context)) { + if (!this.controlCard.movedToNextTurnPile) { + this.controlCard.movedToNextTurnPile = true; + trashCost = this.controlCard.getCost(context); + currentPlayer.playedCards.remove(currentPlayer.playedCards.lastIndexOf(this.controlCard)); + currentPlayer.trash(this.controlCard, null, context); + } + } else if (currentPlayer.getHand().size() > 0) { + Card cardToTrash = currentPlayer.controlPlayer.raze_cardToTrash(context); + if (cardToTrash == null || !currentPlayer.getHand().contains(cardToTrash)) { + Util.playerError(currentPlayer, "Raze trash error, trashing a random card."); + cardToTrash = Util.randomCard(currentPlayer.getHand()); + } + trashCost = cardToTrash.getCost(context); + currentPlayer.getHand().remove(cardToTrash); + currentPlayer.trash(cardToTrash, this.controlCard, context); + } + if (trashCost == 0) + return; + else if (trashCost == 1) { + Card c = game.draw(currentPlayer); + if (c != null) + currentPlayer.hand.add(c); + } else { + ArrayList lookAtCards = new ArrayList(trashCost); + while (lookAtCards.size() < trashCost) { + Card c = game.draw(currentPlayer); + if (c == null) + break; + lookAtCards.add(c); + } + Card cardToKeep = currentPlayer.controlPlayer.raze_cardToKeep(context, lookAtCards.toArray(new Card[0])); + if (cardToKeep == null || !lookAtCards.contains(cardToKeep)) { + Util.playerError(currentPlayer, "Raze keep error. Keeping random card."); + cardToKeep = Util.randomCard(lookAtCards); + } + lookAtCards.remove(cardToKeep); + currentPlayer.getHand().add(cardToKeep); + for (Card c : lookAtCards) { + currentPlayer.discard(c, this.controlCard, context); + } + } + } private void soldier(Game game, MoveContext context, Player currentPlayer) { context.addCoins(context.countAttackCardsInPlayThisTurn() - 1); //without this soldier diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 54cbdce9c..b5c007a02 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -440,6 +440,17 @@ protected Card[] getReactionCards(boolean defended) { } return reactionCards.toArray(new Card[0]); } + + protected boolean containsCardCostingAtLeast(MoveContext context, Iterable toSearch, Card[] toLookFor, int cost) { + for(Card c : toSearch) { + for(Card checkCard : toLookFor) { + if(checkCard.equals(c) && (c.getCost(context) >= cost)) { + return true; + } + } + } + return false; + } @Override public Card[] topOfDeck_orderCards(MoveContext context, Card[] cards) { @@ -3207,6 +3218,62 @@ public boolean miser_shouldTakeTreasure(MoveContext context) { } return false; } + + @Override + public boolean raze_shouldTrashRazePlayed(MoveContext context) { + if (getHand().size() == 0) { + return true; + } + int numLowCostTrashCards = 0; + for(Card c : getHand()) { + for(Card trash : getTrashCards()) { + if(trash.equals(c) && (c.getCost(context) >= Cards.raze.getCost(context))) { + return false; + } + numLowCostTrashCards++; + } + } + //Currently favors keeping the Raze around if we have anything trashy to trash in hand that would + // get at least as many cards than Raze + return numLowCostTrashCards == 0; + } + + @Override + public Card raze_cardToTrash(MoveContext context) { + ArrayList lowTrashCards = new ArrayList(); + for(Card c : getHand()) { + for(Card trash : getTrashCards()) { + if(trash.equals(c) && (c.getCost(context) >= Cards.raze.getCost(context))) { + return c; + } + lowTrashCards.add(c); + } + } + if (!lowTrashCards.isEmpty()) { + return lowTrashCards.get(0); + } + return lowestCard(context, getHand(), false); + } + + @Override + public Card raze_cardToKeep(MoveContext context, Card[] cards) { + Card cardToKeep = null; + + ArrayList goodCards = new ArrayList(); + for (Card c : cards) + if (c instanceof TreasureCard || c instanceof ActionCard) + goodCards.add(c); + + if (goodCards.size() > 0) { + cardToKeep = Util.getMostExpensiveCard(goodCards.toArray(new Card[0])); + } + + if (cardToKeep == null) { + cardToKeep = Util.randomCard(cards); + } + + return cardToKeep; + } @Override public boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) diff --git a/vdom/src/com/vdom/core/CardList.java b/vdom/src/com/vdom/core/CardList.java index fb0c77cb2..a8774d3d3 100644 --- a/vdom/src/com/vdom/core/CardList.java +++ b/vdom/src/com/vdom/core/CardList.java @@ -173,4 +173,9 @@ public Card[] sort(Comparator comp) { Arrays.sort(sorted, comp); return sorted; } + + @Override + public String toString() { + return name + "(" + player.getPlayerName() + "): " + a.toString(); + } } diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 6b86139df..24dbe2fb8 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -701,7 +701,7 @@ public enum Type { // Adventures actionCardsAdventures.add(amulet = new ActionDurationCardImpl.Builder(Cards.Type.Amulet, 3).description("Now and at the start of your next turn, choose one: +1 Coin; or trash a card from your hand; or gain a Silver.").expansion("Adventures").build()); actionCardsAdventures.add(artificer = new ActionCardImpl.Builder(Cards.Type.Artificer, 5).addCards(1).addActions(1).addGold(1).description("Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck.").expansion("Adventures").build()); - actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 5).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is on play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); + actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 5).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is in play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 2).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); @@ -721,7 +721,7 @@ public enum Type { actionCardsAdventures.add(port = new ActionCardImpl.Builder(Cards.Type.Port, 4).addCards(1).addActions(2).description("When you buy this, gain another Port.").expansion("Adventures").build()); actionCardsAdventures.add(ranger = new ActionCardImpl.Builder(Cards.Type.Ranger, 4).addBuys(1).description("Turn your Journey token over (it starts face up). If it's face up, +5 Cards.").expansion("Adventures").build()); actionCardsAdventures.add(ratcatcher = new ActionCardImpl.Builder(Cards.Type.Ratcatcher, 2).addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand.").expansion("Adventures").build()); - actionCardsAdventures.add(raze = new ActionCardImpl.Builder(Cards.Type.Raze, 2).addActions(1).addBuys(1).description("Trash this or a card from your hand. Look at a number of cards from the top of your deck equal to the cost in Coins of the trashed card. Put one into your hand and discard the rest.").expansion("Adventures").build()); + actionCardsAdventures.add(raze = new ActionCardImpl.Builder(Cards.Type.Raze, 2).addActions(1).description("Trash this or a card from your hand. Look at a number of cards from the top of your deck equal to the cost in Coins of the trashed card. Put one into your hand and discard the rest.").expansion("Adventures").build()); actionCardsAdventures.add(relic = new TreasureCardImpl.Builder(Cards.Type.Relic, 5, 2).attack().description("When you play this, each other player puts his -1 Card token on his deck.").expansion("Adventures").build()); actionCardsAdventures.add(royalCarriage = new ActionCardImpl.Builder(Cards.Type.RoyalCarriage, 5).addActions(1).isReserve().description("Put this on your Tavern mat. ~ Directly after resolving an Action, if it's still in play, you may call this, to replay that Action.").expansion("Adventures").build()); actionCardsAdventures.add(storyteller = new ActionCardImpl.Builder(Cards.Type.Storyteller, 5).addGold(1).addActions(1).description("Play up to 3 Treasures from your hand. Pay all of your Coins; +1 Card per Coin paid.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 625cf9e81..8cb5264ed 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2611,6 +2611,32 @@ public boolean miser_shouldTakeTreasure(MoveContext context) { extras[0] = this.getMiserTreasure(); return selectBoolean(context, Cards.miser, extras); } + + @Override + public boolean raze_shouldTrashRazePlayed(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_raze_shouldTrashRazePlayed(context)) { + return super.raze_shouldTrashRazePlayed(context); + } + return selectBoolean(context, Cards.raze); + } + + @Override + public Card raze_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_raze_cardToTrash(context)) { + return super.raze_cardToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setPickType(PickType.TRASH) + .setActionType(ActionType.TRASH).setCardResponsible(Cards.raze); + return getCardFromHand(context, sco); + } + + @Override + public Card raze_cardToKeep(MoveContext context, Card[] cards) { + if(context.isQuickPlay() && shouldAutoPlay_raze_cardToKeep(context)) { + return super.raze_cardToKeep(context, cards); + } + return cards[selectOption(context, Cards.raze, cards)]; + } @Override public boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 96fbd6840..18910364f 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1694,21 +1694,25 @@ public ArrayList getActionsInHand() { // //////////////////////////////////////////// // Card interactions - Adventures Expansion // //////////////////////////////////////////// - public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); + + public abstract AmuletOption amulet_chooseOption(MoveContext context); + public abstract Card amulet_cardToTrash(MoveContext context); public abstract Card[] artificer_cardsToDiscard(MoveContext context); public abstract Card artificer_cardToObtain(MoveContext context, int cost); public abstract Card[] gear_cardsToSetAside(MoveContext context); - public abstract AmuletOption amulet_chooseOption(MoveContext context); - public abstract Card amulet_cardToTrash(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); public abstract boolean miser_shouldTakeTreasure(MoveContext context); + public abstract boolean raze_shouldTrashRazePlayed(MoveContext context); + public abstract Card raze_cardToTrash(MoveContext context); + public abstract Card raze_cardToKeep(MoveContext context, Card[] cards); public abstract int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTotal); - public abstract Card[] bonfire_cardsToTrash(MoveContext context); - - + // /////////////////////////////////////////////// + // Card interactions - Adventures Expansion Events + // /////////////////////////////////////////////// - + public abstract Card[] bonfire_cardsToTrash(MoveContext context); + public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); // //////////////////////////////////////////// // Card interactions - Promotional Cards diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index cb66700bb..17323a2fe 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -824,6 +824,21 @@ public boolean shouldAutoPlay_artificer_cardToObtain(MoveContext context, int co public boolean shouldAutoPlay_miser_shouldTakeTreasure(MoveContext context) { return true; } + + public boolean shouldAutoPlay_raze_shouldTrashRazePlayed(MoveContext context) { + if (getHand().size() == 0) { + return true; + } + return containsCardCostingAtLeast(context, getHand(), getTrashCards(), Cards.raze.getCost(context)); + } + + public boolean shouldAutoPlay_raze_cardToTrash(MoveContext context) { + return containsCardCostingAtLeast(context, getHand(), getTrashCards(), Cards.raze.getCost(context)); + } + + public boolean shouldAutoPlay_raze_cardToKeep(MoveContext context) { + return false; + } public boolean shouldAutoPlay_traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) { return true; diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 674337798..7be5fa098 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -134,12 +134,7 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla card.pile = MyCard.SUPPLYPILE; - if ((c.equals(Cards.bagOfGold)) || - (c.equals(Cards.diadem)) || - (c.equals(Cards.followers)) || - (c.equals(Cards.princess)) || - (c.equals(Cards.trustySteed))) { - + if (c.isPrize()) { card.pile = MyCard.PRIZEPILE; card.isPrize = true; } diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 2b0af7294..44906e590 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -434,6 +434,19 @@ public static ArrayList copy(CardList cards) { return copy; } + + public static ArrayList copy(Iterable cards) { + if (cards == null) { + return null; + } + + ArrayList copy = new ArrayList(); + for (Card card : cards) { + copy.add(card); + } + + return copy; + } public static int getCardCount(CardList cards, Card card) { int count = 0; @@ -457,6 +470,27 @@ public static int getCardCount(ArrayList cards, Card card) { return count; } + + public static boolean areCardsInHand(Card[] cards, MoveContext context) { + return areCardsInList(cards, context.getPlayer().getHand()); + } + + public static boolean areCardsInList(Card[] cards, Iterable list) { + boolean bad = false; + if (cards == null) { + bad = true; + } else { + ArrayList handCopy = Util.copy(list); + for (Card card : cards) { + if (!handCopy.remove(card)) { + bad = true; + break; + } + } + } + return !bad; + } + public static Card getLeastExpensiveCard(Card[] cards) { if (cards == null || cards.length == 0) { return null; From 3bf7020742cec170277006877c4dff44ce91ff17 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 12:34:59 -0700 Subject: [PATCH 010/141] Fixes for Artificer. - Avoid asking player for input if 0 cards in hand. - Avoid discarding invalid cards. - Using gainNewCard instead of takeFromPile --- androminion/res/values/strings-cards.xml | 2 +- .../com/mehtank/androminion/ui/Strings.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 18 ++++++------------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index fc4ed8a2d..8f442a148 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -480,7 +480,7 @@ Amulet Now and at the start of your next turn, choose one: +1 coin; or trash a card from your hand; or gain a Silver. Artificer - Discard any number of cards. You may gain a card costing exactly 1 coin per card discarded, putting it on top of your deck. + Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck. Bridge Troll Each other player takes his -1 coin token. - While this is on play, cards cost 1 coin less on your turns, but not less than 0 coins. Caravan Guard diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 8650f97a0..8ec9b872c 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1142,7 +1142,7 @@ private static void initActionStrings() { getCardName(Cards.remake), getCardName(Cards.remodel), getCardName(Cards.salvager), - /* secretChamber isn't simply, causes error in getActionString() */ + /* secretChamber isn't simple, causes error in getActionString() */ getCardName(Cards.spiceMerchant), getCardName(Cards.squire), getCardName(Cards.stables), diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 8c1d75442..72fc263ab 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -6057,13 +6057,14 @@ private void amulet(Game game, MoveContext context, Player currentPlayer) { private void artificer(Game game, MoveContext context, Player currentPlayer) { int numberOfCards = 0; - Card[] cards = currentPlayer.controlPlayer.artificer_cardsToDiscard(context); + Card[] cards = currentPlayer.getHand().size() == 0 ? null : currentPlayer.controlPlayer.artificer_cardsToDiscard(context); if (cards != null) { for (Card card : cards) { if (card != null) { - hand(currentPlayer).remove(card); - currentPlayer.discard(card, this.controlCard, context); - numberOfCards++; + if (hand(currentPlayer).remove(card)) { + currentPlayer.discard(card, this.controlCard, context); + numberOfCards++; + } } } if (numberOfCards != cards.length) { @@ -6074,14 +6075,7 @@ private void artificer(Game game, MoveContext context, Player currentPlayer) { if (toObtain != null) { // check cost if (toObtain.getCost(context) == numberOfCards) { - toObtain = game.takeFromPile(toObtain); - // could still be null here if the pile is empty. - if (toObtain != null) { - GameEvent event = new GameEvent(GameEvent.Type.CardObtained, context); - event.card = toObtain; - event.responsible = this; - game.broadcastEvent(event); - } + currentPlayer.gainNewCard(toObtain, this.controlCard, context); } } } From 43c0eefe2d4fcbb9601636fb9eded70d48d3afb7 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 14:18:06 -0700 Subject: [PATCH 011/141] Fixes for Messenger. - Added fix for if Trader replaces gained Messenger card. - Avoided put deck in discard choice for Messenger/Chancellor/Scavenger if deck is empty. -Perform Messenger copy gain in turn order. --- .../com/mehtank/androminion/ui/Strings.java | 1 + vdom/src/com/vdom/core/ActionCardImpl.java | 35 ++++++++++++++----- vdom/src/com/vdom/core/BasePlayer.java | 7 ++++ vdom/src/com/vdom/core/IndirectPlayer.java | 19 ++++++++++ vdom/src/com/vdom/core/Player.java | 2 ++ vdom/src/com/vdom/core/QuickPlayPlayer.java | 8 +++++ 6 files changed, 63 insertions(+), 9 deletions(-) diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 8ec9b872c..67113e7e2 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1135,6 +1135,7 @@ private static void initActionStrings() { getCardName(Cards.jackOfAllTrades), getCardName(Cards.journeyman), getCardName(Cards.junkDealer), + getCardName(Cards.messenger), getCardName(Cards.oasis), getCardName(Cards.plaza), getCardName(Cards.rats), diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 72fc263ab..a22ce50b9 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -778,7 +778,7 @@ protected void additionalCardActions(Game game, MoveContext context, Player curr magpie(game, context, currentPlayer); break; case Messenger: - chancellor(game, context, currentPlayer); + messenger(game, context, currentPlayer); break; case Miser: miser(game, context, currentPlayer); @@ -3953,6 +3953,8 @@ private void feast(MoveContext context, Player currentPlayer) { } private void chancellor(Game game, MoveContext context, Player currentPlayer) { + if (currentPlayer.getDeckSize() == 0) + return; boolean discard = currentPlayer.controlPlayer.chancellor_shouldDiscardDeck(context, this.controlCard); if (discard) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); @@ -4137,14 +4139,16 @@ public void isBuying(MoveContext context) { case Messenger: /* This buy is already in totalCardsBoughtThisTurn */ if(context.totalCardsBoughtThisTurn + context.totalEventsBoughtThisTurn == 1) { - Card card = context.getPlayer().controlPlayer.workshop_cardToObtain(context); /*frr18 todo correct name */ + Card card = context.getPlayer().controlPlayer.messenger_cardToObtain(context); if (card != null) { - context.getPlayer().gainNewCard(card, this.controlCard, context); - for (Player player : getAllPlayers()) { - if (player != context.getPlayer()) { - player.gainNewCard(card, this.controlCard, new MoveContext(context.game, player)); - } - } + Card cardGained = context.getPlayer().gainNewCard(card, this.controlCard, context); + if (cardGained.equals(card)) { + for (Player player : context.game.getPlayersInTurnOrder()) { + if (player != context.getPlayer()) { + player.gainNewCard(card, this.controlCard, new MoveContext(context.game, player)); + } + } + } } } break; @@ -4635,7 +4639,7 @@ private void mystic(Game game, MoveContext context, Player currentPlayer) { private void scavenger(Game game, MoveContext context, Player currentPlayer) { - boolean discard = currentPlayer.controlPlayer.scavenger_shouldDiscardDeck(context); + boolean discard = currentPlayer.getDeckSize() == 0 ? false : currentPlayer.controlPlayer.scavenger_shouldDiscardDeck(context); // Discard the entire deck if the player chose to do so if (discard) @@ -6191,6 +6195,19 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) } } } + + private void messenger(Game game, MoveContext context, Player currentPlayer) { + if (currentPlayer.getDeckSize() == 0) + return; + boolean discard = currentPlayer.controlPlayer.messenger_shouldDiscardDeck(context, this.controlCard); + if (discard) { + GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); + game.broadcastEvent(event); + while (currentPlayer.getDeckSize() > 0) { + currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); + } + } + } private void miser(Game game, MoveContext context, Player currentPlayer) { boolean takeTreasure = currentPlayer.controlPlayer.miser_shouldTakeTreasure(context); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index b5c007a02..246f49e5f 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3198,6 +3198,13 @@ public Card[] gear_cardsToSetAside(MoveContext context) { return cards.toArray(new Card[0]); } + + public Card messenger_cardToObtain(MoveContext context) { + return bestCardInPlay(context, 4, true); + } + public boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible) { + return true; + } @Override public boolean miser_shouldTakeTreasure(MoveContext context) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 8cb5264ed..32b01f248 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2601,6 +2601,25 @@ public Card[] gear_cardsToSetAside(MoveContext context) { .setCardResponsible(Cards.gear); return getFromHand(context, sco); } + + @Override + public boolean messenger_shouldDiscardDeck(MoveContext context, + Card responsible) { + if(context.isQuickPlay() && shouldAutoPlay_messenger_shouldDiscardDeck(context, responsible)) { + return super.messenger_shouldDiscardDeck(context, responsible); + } + return selectBoolean(context, responsible); + } + + @Override + public Card messenger_cardToObtain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_messenger_cardToObtain(context)) { + return super.messenger_cardToObtain(context); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) + .setCardResponsible(Cards.messenger).setActionType(ActionType.GAIN); + return getFromTable(context, sco); + } @Override public boolean miser_shouldTakeTreasure(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 18910364f..f631b9dc1 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1701,6 +1701,8 @@ public ArrayList getActionsInHand() { public abstract Card artificer_cardToObtain(MoveContext context, int cost); public abstract Card[] gear_cardsToSetAside(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); + public abstract Card messenger_cardToObtain(MoveContext context); + public abstract boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible); public abstract boolean miser_shouldTakeTreasure(MoveContext context); public abstract boolean raze_shouldTrashRazePlayed(MoveContext context); public abstract Card raze_cardToTrash(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 17323a2fe..beafc1f49 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -820,6 +820,14 @@ public boolean shouldAutoPlay_artificer_cardsToDiscard(MoveContext context) { public boolean shouldAutoPlay_artificer_cardToObtain(MoveContext context, int cost) { return false; } + + public boolean shouldAutoPlay_messenger_shouldDiscardDeck(MoveContext context, Card responsible) { + return true; + } + + public boolean shouldAutoPlay_messenger_cardToObtain(MoveContext context) { + return false; + } public boolean shouldAutoPlay_miser_shouldTakeTreasure(MoveContext context) { return true; From 2baf0a6608984675885ee67d03c541c3bfbb1cb4 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 15:28:04 -0700 Subject: [PATCH 012/141] Fix for Alms: adding own Player handler and UI text. Making "[Card] gained" game message say "[Event] bought" for events. --- androminion/res/values/strings-ui.xml | 1 + .../src/com/mehtank/androminion/ui/GameTable.java | 5 +++-- .../src/com/mehtank/androminion/ui/Strings.java | 3 ++- vdom/src/com/vdom/core/BasePlayer.java | 6 ++++++ vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/IndirectPlayer.java | 10 ++++++++++ vdom/src/com/vdom/core/Player.java | 1 + vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 ++++ vdom/src/com/vdom/core/TreasureCardImpl.java | 2 +- 9 files changed, 29 insertions(+), 5 deletions(-) diff --git a/androminion/res/values/strings-ui.xml b/androminion/res/values/strings-ui.xml index f5513590b..19d976a80 100644 --- a/androminion/res/values/strings-ui.xml +++ b/androminion/res/values/strings-ui.xml @@ -130,6 +130,7 @@ Loading game… Click again to quit. %1$s gained + %1$s bought %1$s trashed %1$s revealed %1$s revealed (from hand) diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 452be0b92..416702020 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -1096,13 +1096,14 @@ private void addPlayer(String name) { } /** - * A player obtained a card and we notify the user + * A player obtained a card/event 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)); + boolean isEvent = GameTableViews.cardsInPlay.get(i).isEvent; + return top.getString(isEvent ? R.string.eventBought : R.string.obtained, showCard(i, s, CardAnimator.ShowCardType.OBTAINED)); } /** diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 67113e7e2..49ea85b3e 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1166,7 +1166,8 @@ private static void initActionStrings() { getCardName(Cards.dungeon), getCardName(Cards.raze), getCardName(Cards.storyteller), - getCardName(Cards.treasureTrove) + /*Adventures Events*/ + getCardName(Cards.alms) )); actionStringMap = new HashMap(); actionStringMap.put(getCardName(Cards.bureaucrat), getString(R.string.bureaucrat_part)); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 246f49e5f..9252ee1b1 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3202,6 +3202,7 @@ public Card[] gear_cardsToSetAside(MoveContext context) { public Card messenger_cardToObtain(MoveContext context) { return bestCardInPlay(context, 4, true); } + public boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible) { return true; } @@ -3297,6 +3298,11 @@ public int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTo return wineMerchantTotal; } + @Override + public Card alms_cardToObtain(MoveContext context) { + return bestCardInPlay(context, 4, true); + } + public Card[] bonfire_cardsToTrash(MoveContext context) { return pickOutCards(context.getPlayer().playedCards, 2, getTrashCards()); } diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 9757e79da..bab6f47d4 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -89,7 +89,7 @@ public void alms(MoveContext context) { } } if (noTreasureCard) { - Card card = context.player.controlPlayer.workshop_cardToObtain(context); /*frr18 todo right name*/ + Card card = context.player.controlPlayer.alms_cardToObtain(context); if (card != null) { if (card.getCost(context) <= 4) { context.player.gainNewCard(card, this.controlCard, context); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 32b01f248..8002c1da4 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2674,6 +2674,16 @@ public int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTo } return selectInt(context, Cards.wineMerchant, wineMerchantTotal); } + + @Override + public Card alms_cardToObtain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_alms_cardToObtain(context)) { + return super.alms_cardToObtain(context); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) + .setCardResponsible(Cards.alms).setActionType(ActionType.GAIN); + return getFromTable(context, sco); + } @Override public Card[] bonfire_cardsToTrash(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index f631b9dc1..a8ceed613 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1713,6 +1713,7 @@ public ArrayList getActionsInHand() { // Card interactions - Adventures Expansion Events // /////////////////////////////////////////////// + public abstract Card alms_cardToObtain(MoveContext context); public abstract Card[] bonfire_cardsToTrash(MoveContext context); public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index beafc1f49..cf882cd5c 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -855,6 +855,10 @@ public boolean shouldAutoPlay_traveller_shouldExchange(MoveContext context, Card public boolean shouldAutoPlay_cleanup_wineMerchantToDiscard(MoveContext context) { return true; } + + public boolean shouldAutoPlay_alms_cardToObtain(MoveContext context) { + return false; + } public boolean shouldAutoPlay_scoutingParty_cardToDiscard(MoveContext context) { return false; diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 5e619fabf..a52c4409a 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -316,7 +316,7 @@ public void masterpiece(MoveContext context) /*Adventures*/ protected void treasureTrove(MoveContext context, Player player, Game game) { context.getPlayer().gainNewCard(Cards.gold, this.controlCard, context); - context.getPlayer().gainNewCard(Cards.copper, this.controlCard, context); + context.getPlayer().gainNewCard(Cards.copper, this.controlCard, context); } protected void relic(MoveContext context, Player player, Game game) { From 9de61e3f7869340bea1bb422ad28c3a84b52bba9 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 17:19:38 -0700 Subject: [PATCH 013/141] Adding UI messing indiciating which card is having you play treasure cards (for Storyteller and Black Market). --- androminion/res/values/strings-cards.xml | 2 +- .../src/com/mehtank/androminion/ui/GameTable.java | 2 ++ vdom/src/com/vdom/core/ActionCardImpl.java | 4 ++-- vdom/src/com/vdom/core/BasePlayer.java | 2 +- vdom/src/com/vdom/core/Game.java | 8 ++++---- vdom/src/com/vdom/core/IndirectPlayer.java | 9 +++++---- vdom/src/com/vdom/core/Player.java | 2 +- vdom/src/com/vdom/players/VDomPlayerSarah.java | 4 ++-- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index 8f442a148..efe75d10c 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -538,7 +538,7 @@ Soldier +1 coin per other Attack you have in play. Each other player with 4 or more cards in hand discards a card. ~ When you discard this from play, you may exchange it for a Fugitive. Storyteller - Play up to 3 Treasures from your hand. Pay all of your coins; +1 Card per coin paid. + Play up to 3 Treasures from your hand. Pay all of your Coins; +1 Card per Coin paid. Swamp Hag Until your next turn, when any other player buys a card, he gains a Curse. Teacher diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 416702020..3daf58589 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -698,6 +698,8 @@ public void selectCard(SelectCardOptions sco, String s, int maxOpened, boolean e s = Strings.getString(R.string.part_play); } else if (sco.isTreasurePhase) { s = Strings.getString(R.string.use_for_money); + if (sco.cardResponsible != null) + s += " [" + Strings.getCardName(sco.cardResponsible) +"]"; } else if (s == null) { // TODO(matt): maybe these methods could be named better... s = Strings.getActionCardText(sco); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index a22ce50b9..ab9061360 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1124,7 +1124,7 @@ private void blackMarket(Game game, MoveContext context, Player currentPlayer) { } // play treasures - context.game.playTreasures(currentPlayer, context, -1); + context.game.playTreasures(currentPlayer, context, -1, this.controlCard); // get one buy from BlackMarkt pile ArrayList canBuy = new ArrayList(); @@ -6305,7 +6305,7 @@ private void soldier(Game game, MoveContext context, Player currentPlayer) { private void storyteller(Game game, MoveContext context, Player currentPlayer) { // play up to 3 treasures - context.game.playTreasures(currentPlayer, context, 3); + context.game.playTreasures(currentPlayer, context, 3, this.controlCard); int coins = context.getCoins(); context.spendCoins(coins); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 9252ee1b1..e91b16b55 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -1528,7 +1528,7 @@ public WatchTowerOption watchTower_chooseOption(MoveContext context, Card card) } @Override - public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards) { + public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards, Card responsible) { ArrayList ret = new ArrayList(); ArrayList cardArray = new ArrayList(); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index d6a4d67c9..59a9262e2 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -258,7 +258,7 @@ void start() throws ExitException { // ///////////////////////////////// // Select Treasure for Buy // ///////////////////////////////// - playTreasures(player, context, -1); + playTreasures(player, context, -1, null); // Spend Guilds coin tokens if applicable playGuildsTokens(player, context); @@ -364,7 +364,7 @@ public int cardsInLowestPiles (int numPiles) { return count; } - protected void playTreasures(Player player, MoveContext context, int maxCards) { + protected void playTreasures(Player player, MoveContext context, int maxCards, Card responsible) { // storyteller sets maxCards != -1 if (!context.blackMarketBuyPhase && maxCards == -1) { context.buyPhase = true; @@ -373,7 +373,7 @@ protected void playTreasures(Player player, MoveContext context, int maxCards) { boolean selectingCoins = playerShouldSelectCoinsToPlay(context, player.getHand()); if (maxCards != -1) selectingCoins = true;// storyteller ArrayList treasures = null; - treasures = (selectingCoins) ? player.controlPlayer.treasureCardsToPlayInOrder(context, maxCards) : player.getTreasuresInHand(); + treasures = (selectingCoins) ? player.controlPlayer.treasureCardsToPlayInOrder(context, maxCards, responsible) : player.getTreasuresInHand(); while (treasures != null && !treasures.isEmpty() && maxCards != 0) { while (!treasures.isEmpty() && maxCards != 0) { @@ -384,7 +384,7 @@ protected void playTreasures(Player player, MoveContext context, int maxCards) { } } if (maxCards != 0) - treasures = (selectingCoins) ? player.controlPlayer.treasureCardsToPlayInOrder(context, maxCards) : player.getTreasuresInHand(); + treasures = (selectingCoins) ? player.controlPlayer.treasureCardsToPlayInOrder(context, maxCards, responsible) : player.getTreasuresInHand(); } } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 8002c1da4..93796e8ed 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -249,10 +249,10 @@ public Card doBuy(MoveContext context) { } @Override - public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards) { + public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards, Card responsible) { // storyteller sets maxCards != -1 if(context.isQuickPlay()) { - return super.treasureCardsToPlayInOrder(context, maxCards); + return super.treasureCardsToPlayInOrder(context, maxCards, responsible); } int treasureCount = 0; @@ -266,7 +266,8 @@ public ArrayList treasureCardsToPlayInOrder(MoveContext context, i } SelectCardOptions sco = new SelectCardOptions().isTreasure().setPassable().isTreasurePhase() - .setCount(treasureCount).ordered().setPickType(PickType.SELECT_WITH_ALL); + .setCount(treasureCount).ordered().setPickType(PickType.SELECT_WITH_ALL) + .setCardResponsible(responsible); Card[] cards = getFromHand(context, sco); if (cards == null) { return null; @@ -283,7 +284,7 @@ public ArrayList treasureCardsToPlayInOrder(MoveContext context, i } return treasures; } else - return super.treasureCardsToPlayInOrder(context, maxCards); + return super.treasureCardsToPlayInOrder(context, maxCards, responsible); } ArrayList treasures = new ArrayList(); diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index a8ceed613..93fda8dad 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1479,7 +1479,7 @@ public ArrayList getActionsInHand() { public abstract WatchTowerOption watchTower_chooseOption(MoveContext context, Card card); - public abstract ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards); + public abstract ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards, Card responsible); // //////////////////////////////////////////// // Card interactions - cards from Cornucopia diff --git a/vdom/src/com/vdom/players/VDomPlayerSarah.java b/vdom/src/com/vdom/players/VDomPlayerSarah.java index 02479c2c4..433db332c 100644 --- a/vdom/src/com/vdom/players/VDomPlayerSarah.java +++ b/vdom/src/com/vdom/players/VDomPlayerSarah.java @@ -635,7 +635,7 @@ public Card doBuy(MoveContext context) { } @Override - public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards) { + public ArrayList treasureCardsToPlayInOrder(MoveContext context, int maxCards, Card responsible) { if(context.cardInGame(Cards.grandMarket)) { final ArrayList cards = new ArrayList(); int coinWithoutCopper = 0; @@ -652,7 +652,7 @@ public ArrayList treasureCardsToPlayInOrder(MoveContext context, i } } - return super.treasureCardsToPlayInOrder(context, maxCards); + return super.treasureCardsToPlayInOrder(context, maxCards, responsible); } From 6ec2c1bd505758e1ed95cdfc26688c7e864528b9 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 23:25:34 -0700 Subject: [PATCH 014/141] Fixing Dungeon cost. Reworking Dungeon/Horse Traders discard logic to not ask player which cards to discard if hand <= 2 cards. --- vdom/src/com/vdom/core/ActionCardImpl.java | 47 +++++++++------------- vdom/src/com/vdom/core/Cards.java | 2 +- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index ab9061360..935a711c0 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -2076,35 +2076,28 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { } private void horseTradersDungeon(MoveContext context, Player currentPlayer) { - Card[] cardsToDiscard = currentPlayer.controlPlayer.horseTradersDungeon_cardsToDiscard(context, this.controlCard); - boolean bad = false; - - if (cardsToDiscard == null) { - bad = true; - } else if (currentPlayer.hand.size() < 2 && cardsToDiscard.length != currentPlayer.hand.size()) { - bad = true; - } else if (cardsToDiscard.length != 2) { - bad = true; - } else { - ArrayList copy = Util.copy(currentPlayer.hand); - for (Card cardToKeep : cardsToDiscard) { - if (!copy.remove(cardToKeep)) { - bad = true; - break; + CardList hand = currentPlayer.getHand(); + if (hand.size() == 0) + return; + Card[] cardsToDiscard; + if (hand.size() <= 2) { + cardsToDiscard = new Card[currentPlayer.getHand().size()]; + for (int i = 0; i < cardsToDiscard.length; ++i) { + cardsToDiscard[i] = hand.get(i); + } + } else { + cardsToDiscard = currentPlayer.controlPlayer.horseTradersDungeon_cardsToDiscard(context, this.controlCard); + if (cardsToDiscard == null || cardsToDiscard.length != 2 || !Util.areCardsInHand(cardsToDiscard, context)) { + if (currentPlayer.hand.size() >= 2) { + Util.playerError(currentPlayer, "Horse Traders discard error, just discarding the first 2."); + } + cardsToDiscard = new Card[Math.min(2, currentPlayer.hand.size())]; + for (int i = 0; i < cardsToDiscard.length; i++) { + cardsToDiscard[i] = currentPlayer.hand.get(i); } } - } - - if (bad) { - if (currentPlayer.hand.size() >= 2) { - Util.playerError(currentPlayer, "Horse Traders discard error, just discarding the first 2."); - } - cardsToDiscard = new Card[Math.min(2, currentPlayer.hand.size())]; - for (int i = 0; i < cardsToDiscard.length; i++) { - cardsToDiscard[i] = currentPlayer.hand.get(i); - } - } - + } + for (Card card : cardsToDiscard) { currentPlayer.hand.remove(card); currentPlayer.discard(card, this.controlCard, context); diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 24dbe2fb8..6cb3765dd 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -705,7 +705,7 @@ public enum Type { actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 2).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); - actionCardsAdventures.add(dungeon = new ActionDurationCardImpl.Builder(Cards.Type.Dungeon, 4).addCards(2).addActions(1).description("Discard 2 cards. At the start of your next turn: +2 Cards, then discard 2 cards.").expansion("Adventures").build()); + actionCardsAdventures.add(dungeon = new ActionDurationCardImpl.Builder(Cards.Type.Dungeon, 3).addCards(2).addActions(1).description("Discard 2 cards. At the start of your next turn: +2 Cards, then discard 2 cards.").expansion("Adventures").build()); actionCardsAdventures.add(duplicate = new ActionCardImpl.Builder(Cards.Type.Duplicate, 3).isReserve().description("Put this on your Tavern mat. ~ When you gain a card costing up to 6 Coins, you may call this, to gain a copy of that card.").expansion("Adventures").build()); actionCardsAdventures.add(gear = new ActionDurationCardImpl.Builder(Cards.Type.Gear, 3).addCards(2).description("Set aside up to 2 cards from your hand face down. At the start of your next turn, put them into your hand.").expansion("Adventures").build()); actionCardsAdventures.add(giant = new ActionCardImpl.Builder(Cards.Type.Giant, 5).attack().description("Turn your Journey token over (it starts face up). If it's face down, +1 Coin. If it's face up, +5 Coins, and each other player reveals the top card of his deck, trashes it if it costs from 3 to 6 Coins, and otherwise discards it and gains a Curse.").expansion("Adventures").build()); From 1b7bf568c0f74f612c68976f0ec028b65f63ef13 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 30 Dec 2015 23:49:26 -0700 Subject: [PATCH 015/141] Amulet: fixing Player errors to pick valid choices. --- androminion/res/values/strings-cards.xml | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 39 +++++++++++----------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index efe75d10c..e8ea12069 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -478,7 +478,7 @@ You may trash a Treasure from your hand. Each other player with 5 or more cards in hand discards a copy of it (or reveals a hand without it). Gain a Treasure card costing up to 3 Coins more than the trashed card, putting it on top of your deck. Amulet - Now and at the start of your next turn, choose one: +1 coin; or trash a card from your hand; or gain a Silver. + Now and at the start of your next turn, choose one: +1 Coin; or trash a card from your hand; or gain a Silver. Artificer Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck. Bridge Troll diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 935a711c0..3f48c1fe1 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -17,6 +17,7 @@ import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; import com.vdom.core.MoveContext.PileSelection; +import com.vdom.core.Player.AmuletOption; import com.vdom.core.Player.JesterOption; import com.vdom.core.Player.SpiceMerchantOption; import com.vdom.core.Player.TournamentOption; @@ -6027,28 +6028,26 @@ private void amulet(Game game, MoveContext context, Player currentPlayer) { Player.AmuletOption option = currentPlayer.controlPlayer.amulet_chooseOption(context); if (option == null) { - Util.playerError(currentPlayer, "Amulet option error, ignoring."); - } else { - if (option == Player.AmuletOption.AddGold) { - context.addCoins(1); - } else if (option == Player.AmuletOption.GainSilver) { - currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); - } else if (option == Player.AmuletOption.TrashCard) { - CardList hand = currentPlayer.getHand(); - if (hand.size() == 0) { - return; - } + Util.playerError(currentPlayer, "Amulet option error, choosing +(1) Coin."); + option = AmuletOption.AddGold; + } + if (option == Player.AmuletOption.AddGold) { + context.addCoins(1); + } else if (option == Player.AmuletOption.GainSilver) { + currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); + } else if (option == Player.AmuletOption.TrashCard) { + CardList hand = currentPlayer.getHand(); + if (hand.size() == 0) { + return; + } - Card cardToTrash = currentPlayer.controlPlayer.amulet_cardToTrash(context); - if (cardToTrash == null) { - Util.playerError(currentPlayer, "Amulet card to trash was null, not trashing anything."); - } else if (!currentPlayer.hand.contains(cardToTrash)) { - Util.playerError(currentPlayer, "Amulet card to trash is not in your hand, not trashing anything."); - } else { - currentPlayer.hand.remove(cardToTrash); - currentPlayer.trash(cardToTrash, this.controlCard, context); - } + Card cardToTrash = currentPlayer.controlPlayer.amulet_cardToTrash(context); + if (cardToTrash == null || !currentPlayer.hand.contains(cardToTrash)) { + Util.playerError(currentPlayer, "Amulet card to trash error, trashing random card."); + cardToTrash = Util.randomCard(currentPlayer.getHand()); } + currentPlayer.hand.remove(cardToTrash); + currentPlayer.trash(cardToTrash, this.controlCard, context); } } From aa218da3d19bab3fdc81a310bad52b7acf43fa2f Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 31 Dec 2015 00:21:24 -0700 Subject: [PATCH 016/141] Fixing Caravan Guard cost. Fixing Caravan Guard reaction to play card instead of imitate effects (allows +1 Card/+1 Coin Tokens to have effect if needed). --- vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/Util.java | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 6cb3765dd..24665fabb 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -702,7 +702,7 @@ public enum Type { actionCardsAdventures.add(amulet = new ActionDurationCardImpl.Builder(Cards.Type.Amulet, 3).description("Now and at the start of your next turn, choose one: +1 Coin; or trash a card from your hand; or gain a Silver.").expansion("Adventures").build()); actionCardsAdventures.add(artificer = new ActionCardImpl.Builder(Cards.Type.Artificer, 5).addCards(1).addActions(1).addGold(1).description("Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck.").expansion("Adventures").build()); actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 5).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is in play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); - actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 2).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); + actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 3).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); actionCardsAdventures.add(dungeon = new ActionDurationCardImpl.Builder(Cards.Type.Dungeon, 3).addCards(2).addActions(1).description("Discard 2 cards. At the start of your next turn: +2 Cards, then discard 2 cards.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 44906e590..8a0bac616 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -404,18 +404,15 @@ static boolean doBeggar(MoveContext context, Game game, Player player, Card resp } static boolean doCaravanGuard(MoveContext context, Game game, Player player, Card responsible) { - Card caravanGuard = null; + ActionCardImpl caravanGuard = null; for (Card card : player.hand) { if (card.equals(Cards.caravanGuard)) { - caravanGuard = card; + caravanGuard = (ActionCardImpl) card; } } if (caravanGuard != null) { - player.hand.remove(caravanGuard); - player.nextTurnCards.add((DurationCard) caravanGuard); - game.drawToHand(player, responsible); - + caravanGuard.play(game, context, true); return true; } From 828856d504dcbcb2ddaf3f75ae3802cc44bbfe3b Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 31 Dec 2015 01:56:24 -0700 Subject: [PATCH 017/141] Fix for Caravan Guard: preventing Cards played during another player's turn from appearing in the UI Played area. Making UI attack event for Giant happen when attack actually affects other player. --- androminion/res/values/strings-cards.xml | 2 +- .../src/com/mehtank/androminion/ui/GameTable.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 7 +++---- vdom/src/com/vdom/core/Game.java | 4 ++++ vdom/src/com/vdom/core/RemotePlayer.java | 9 ++++++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index e8ea12069..6e5571867 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -502,7 +502,7 @@ Gear Set aside up to 2 cards from your hand face down. At the start of your next turn, put them into your hand. Giant - Turn your Journey token over (it starts face up). If it\'s face down, +1 coin. If it\'s face up, +5 coins, and each other player reveals the top card of his deck, trashes it if it costs from 3 to 6 coins, and otherwise discards it and gains a Curse. + Turn your Journey token over (it starts face up). If it\'s face down, +1 Coin. If it\'s face up, +5 Coins, and each other player reveals the top card of his deck, trashes it if it costs from 3 to 6 Coins, and otherwise discards it and gains a Curse. Guide Put this on your Tavern mat. - At the start of your turn, you may call this, to discard your hand and draw 5 cards. Haunted Woods diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 3daf58589..c7fbbf165 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -472,7 +472,7 @@ private void cannotSelect() { */ boolean isAcceptable(MyCard c, CardGroup parent) { if (sco.fromHand && (parent != hand)) return false; - else if (sco.fromPlayed && (parent != played)) return false; + else if (sco.fromPlayed && (parent != played)) return false; // TODO: prevent throned plays from being selected from played group else if (sco.fromTable) { // if (!sco.allowEmpty) { // if (lastSupplySizes[c.id] == 0) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 3f48c1fe1..d68a2a4c8 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -6129,13 +6129,13 @@ private void giant(Game game, MoveContext context, Player currentPlayer) for (Player targetPlayer : game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { playersToAttack.add(targetPlayer); - targetPlayer.attacked(this.controlCard, context); } } if(currentPlayer.flipJourneyToken(context)) { context.addCoins(5); for (Player targetPlayer : playersToAttack) { + targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); Card card = game.draw(targetPlayer); @@ -6151,9 +6151,8 @@ private void giant(Game game, MoveContext context, Player currentPlayer) } } } - } else - { - context.addCoins(1); + } else { + context.addCoins(1); } } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 59a9262e2..6b7d7e988 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -2845,6 +2845,10 @@ public Player getNextPlayer() { return players[next]; } + + public Player getCurrentPlayer() { + return players[playersTurn]; + } public Player[] getPlayersInTurnOrder() { Player[] ordered = new Player[numPlayers]; diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 7be5fa098..2e1e41c97 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -619,10 +619,10 @@ public void gameEvent(GameEvent event) { extras.add(islandSize); int nativeVillageSize = event.player.nativeVillage.size(); extras.add(nativeVillageSize); - } else if (event.getType() == Type.PlayingAction || event.getType() == Type.PlayingDurationAction) { + } else if (isPlayersTurn(event) && event.getType() == Type.PlayingAction || event.getType() == Type.PlayingDurationAction) { playedCards.add(event.getCard()); playedCardsNew.add(event.newCard); - } else if (event.getType() == Type.PlayingCoin) { + } else if (isPlayersTurn(event) && event.getType() == Type.PlayingCoin) { playedCards.add(event.getCard()); playedCardsNew.add(event.newCard); } else if (event.getType() == Type.CardObtained) { @@ -702,7 +702,10 @@ public void gameEvent(GameEvent event) { } } - private void checkForAchievements(MoveContext context, Type eventType) { + private boolean isPlayersTurn(GameEvent event) { + return event.context.game.getCurrentPlayer().equals(event.player); + } + private void checkForAchievements(MoveContext context, Type eventType) { if (eventType == Type.GameOver) { int provinces = 0; int curses = 0; From 8be92503af545e55bebc7d7cf7c2cb1a14f2a05b Mon Sep 17 00:00:00 2001 From: dominionator Date: Fri, 1 Jan 2016 11:12:03 -0700 Subject: [PATCH 018/141] Implemented Adventures player supply pile tokens. UI is still a work in progress. Implemented Adventures events: Ferry, Lost Arts, Pathfinding, Plan, Seaway, Training --- androminion/res/drawable/circulartoken.xml | 15 +++ androminion/res/drawable/rectangulartoken.xml | 16 +++ androminion/res/layout/view_card.xml | 9 ++ androminion/res/values/colors.xml | 15 +++ androminion/res/values/strings-cards.xml | 6 +- androminion/res/values/strings-server.xml | 13 +++ .../com/mehtank/androminion/ui/CardView.java | 100 +++++++++++++++++- .../com/mehtank/androminion/ui/FinalView.java | 6 +- .../com/mehtank/androminion/ui/GameTable.java | 24 +++-- .../com/mehtank/androminion/ui/Strings.java | 28 ++++- .../mehtank/androminion/util/CardGroup.java | 6 +- vdom/src/com/vdom/api/GameEvent.java | 14 ++- vdom/src/com/vdom/comms/GameStatus.java | 9 +- vdom/src/com/vdom/core/ActionCardImpl.java | 11 +- vdom/src/com/vdom/core/BasePlayer.java | 36 ++++++- vdom/src/com/vdom/core/CardImpl.java | 1 + vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 76 ++++++++++++- vdom/src/com/vdom/core/Game.java | 71 ++++++++++++- vdom/src/com/vdom/core/IndirectPlayer.java | 70 ++++++++++++ vdom/src/com/vdom/core/Player.java | 7 ++ vdom/src/com/vdom/core/PlayerSupplyToken.java | 23 ++++ vdom/src/com/vdom/core/QuickPlayPlayer.java | 28 +++++ vdom/src/com/vdom/core/RemotePlayer.java | 18 ++++ 24 files changed, 569 insertions(+), 35 deletions(-) create mode 100644 androminion/res/drawable/circulartoken.xml create mode 100644 androminion/res/drawable/rectangulartoken.xml create mode 100644 vdom/src/com/vdom/core/PlayerSupplyToken.java diff --git a/androminion/res/drawable/circulartoken.xml b/androminion/res/drawable/circulartoken.xml new file mode 100644 index 000000000..c6534030b --- /dev/null +++ b/androminion/res/drawable/circulartoken.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/androminion/res/drawable/rectangulartoken.xml b/androminion/res/drawable/rectangulartoken.xml new file mode 100644 index 000000000..cb19ab66b --- /dev/null +++ b/androminion/res/drawable/rectangulartoken.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/androminion/res/layout/view_card.xml b/androminion/res/layout/view_card.xml index 7f1288ec3..14f91eec7 100644 --- a/androminion/res/layout/view_card.xml +++ b/androminion/res/layout/view_card.xml @@ -47,6 +47,15 @@ android:background="@drawable/embargos" android:textColor="@android:color/white" android:visibility="gone" /> + + #806F49 #B0AFA7 #E6DEC8 + + #d9562b + #508db9 + #e5d63a + #24ad4c + #f2982a + #dadbdc + + #a44121 + #3b6888 + #b5a92e + #1c883c + #c47b22 + #abacad + \ No newline at end of file diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index 6e5571867..5cfc17cca 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -565,10 +565,10 @@ Expedition Draw 2 extra cards for your next hand. Ferry - Move your -2 coins cost token to an Action Supply pile (cards from that pile cost 2 coins less on your turns, but not less than 0 coins). + Move your -2 cost token to an Action Supply pile (cards from that pile cost 2 Coins less on your turns, but not less than 0 Coins). Inheritance Once per game: Set aside a non-Victory Action card from the Supply costing up to 4 Coins. Move your Estate token to it (your Estates gain the abilities and types of that card). - LostArts + Lost Arts Move your +1 Action token to an Action Supply pile (when you play a card from that pile, you first get +1 Action). Mission Once per turn: If the previous turn wasn\'t yours, take another turn after this one, in which you can\'t buy cards. @@ -591,7 +591,7 @@ Trade Trash up to 2 cards from your hand. Gain a Silver per card you trashed. Training - Move your +1 coin token to an Action Supply pile (when you play a card from that pile, you first get +1 coin). + Move your +1 Coin token to an Action Supply pile (when you play a card from that pile, you first get +1 Coin). TravellingFair When you gain a card this turn, you may put it on top of your deck. diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index f462d2961..a42dc0a31 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -41,12 +41,19 @@ %1$s option play buy + move your -2 cost token to + move your +1 Card token to + move your +1 Action token to + move your +1 Buy token to + move your +1 Coin token to + move your Trashing token to discard pile hand Select a card from the table to %1$s Select an Attack card from the table to %1$s + Select an Action card from the table to %1$s Select a card from the table that costs exactly (%1$s) to %2$s Select an Action card from the table that costs exactly (%1$s) to %2$s Select a card from the table that costs at most (%1$s) to %2$s @@ -102,6 +109,12 @@ Game over Embargo + +1 Card token moved to + +1 Action token moved to + +1 Buy token moved to + +1 Coin token moved to + -2 cost token moved to + Trashing token moved to Cards on island Cards on native village Status diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index aab5d5e82..c04dca840 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -14,6 +14,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; import android.preference.PreferenceManager; @@ -27,6 +30,7 @@ import android.view.animation.AlphaAnimation; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import com.mehtank.androminion.R; @@ -36,6 +40,7 @@ import com.mehtank.androminion.util.HapticFeedback; import com.mehtank.androminion.util.HapticFeedback.AlertType; import com.vdom.comms.MyCard; +import com.vdom.core.PlayerSupplyToken; /** * Corresponds to a single card that is visible on the 'table' @@ -47,6 +52,7 @@ public class CardView extends FrameLayout implements OnLongClickListener, Checka private TextView name; private View cardBox; private TextView cost, countLeft, embargos; + private LinearLayout tokens; private TextView checked; private TextView cardDesc; @@ -57,6 +63,7 @@ public class CardView extends FrameLayout implements OnLongClickListener, Checka CardGroup parent; private CardState state; + /** * Information about a card type opened, onTable, indicator, order * @@ -125,9 +132,10 @@ else if (viewstyle.equals("viewstyle-descriptive")) cost = (TextView) findViewById(R.id.cost); countLeft = (TextView) findViewById(R.id.countLeft); embargos = (TextView) findViewById(R.id.embargos); + tokens = (LinearLayout) findViewById(R.id.tokens); checked = (TextView) findViewById(R.id.checked); cardDesc = (TextView) findViewById(R.id.cardDesc); - + state = new CardState(null); if (c != null) { @@ -354,6 +362,95 @@ public void setEmbargos(int s) { embargos.setVisibility(GONE); } } + + public void setTokens(int[][] newTokens) { + tokens.removeAllViews(); + for (int i = 0; i < newTokens.length; ++i) { + int[] players = newTokens[i]; + for (int tokenId : players) { + View tokenView = getViewForToken(i, tokenId); + if (tokenView != null) + tokens.addView(tokenView); + } + } + } + + private View getViewForToken(int player, int tokenId) { + int backgroundId = R.drawable.circulartoken;; + String text; + switch(PlayerSupplyToken.getById(tokenId)) { + case PlusOneCard: + backgroundId = R.drawable.rectangulartoken; + text = "+1"; + break; + case PlusOneAction: + text = "+A"; + break; + case PlusOneBuy: + text = "+B"; + break; + case PlusOneCoin: + text = "+1"; + break; + case MinusTwoCost: + text = "-2"; + break; + case Trashing: + text = "X"; + break; + default: + return null; + } + float sd = getResources().getDisplayMetrics().scaledDensity; + float dp = getResources().getDisplayMetrics().density; + GradientDrawable background = (GradientDrawable)getResources().getDrawable(backgroundId).mutate(); + background.setColor(getPlayerColor(player)); + background.setStroke((int)(2 * dp), getPlayerStrokeColor(player)); + TextView token = new TextView(getContext()); + token.setBackgroundDrawable(background); + int pad = (int)dp; + token.setTextSize(sd * 8); + token.setTextColor(Color.BLACK); + token.setPadding(pad, pad, pad, pad); + token.setText(text); + return token; + } + + public int getPlayerColor(int playerNumber) { + switch(playerNumber) { + case 0: + return getResources().getColor(R.color.player1Color); + case 1: + return getResources().getColor(R.color.player2Color); + case 2: + return getResources().getColor(R.color.player3Color); + case 3: + return getResources().getColor(R.color.player4Color); + case 4: + return getResources().getColor(R.color.player5Color); + case 5: + default: + return getResources().getColor(R.color.player6Color); + } + } + + private int getPlayerStrokeColor(int playerNumber) { + switch(playerNumber) { + case 0: + return getResources().getColor(R.color.player1LineColor); + case 1: + return getResources().getColor(R.color.player2LineColor); + case 2: + return getResources().getColor(R.color.player3LineColor); + case 3: + return getResources().getColor(R.color.player4LineColor); + case 4: + return getResources().getColor(R.color.player5LineColor); + case 5: + default: + return getResources().getColor(R.color.player6LineColor); + } + } public void setCost(int newCost, boolean overpay) { cost.setText(" " + newCost + (overpay ? "+" : "") + " "); @@ -617,5 +714,4 @@ public static boolean isDownloadManagerAvailable(Context context) { return false; } } - } diff --git a/androminion/src/com/mehtank/androminion/ui/FinalView.java b/androminion/src/com/mehtank/androminion/ui/FinalView.java index c9b99fa4c..6c7d28706 100644 --- a/androminion/src/com/mehtank/androminion/ui/FinalView.java +++ b/androminion/src/com/mehtank/androminion/ui/FinalView.java @@ -21,15 +21,17 @@ public class FinalView extends FrameLayout implements OnClickListener { private GameTable gt; private int[] cardCounts, embargos; + private int[][][] tokens; private TextView name; public ToggleButton showCards; - public FinalView(Context context, GameTable gt, String nameStr, int numTurns, int[] embargos, int numCards, int[] cardCounts, int vp, boolean winner) { + public FinalView(Context context, GameTable gt, String nameStr, int numTurns, int[] embargos, int[][][] tokens, int numCards, int[] cardCounts, int vp, boolean winner) { super(context); this.gt = gt; this.embargos = embargos; + this.tokens = tokens; this.cardCounts = cardCounts; LayoutInflater.from(context).inflate(R.layout.view_final, this, true); @@ -48,7 +50,7 @@ public FinalView(Context context, GameTable gt, String nameStr, int numTurns, in public void onClick(View v) { if (showCards.isChecked()) { gt.uncheckAllShowCardsButtons(); - gt.setSupplySizes(cardCounts, embargos); + gt.setSupplySizes(cardCounts, embargos, tokens); showCards.setChecked(true); } else gt.uncheckAllShowCardsButtons(); diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index c7fbbf165..14177c301 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -512,6 +512,8 @@ else if (sco.fromTable) { private int[] lastSupplySizes; private int[] lastEmbargos; + + private int[][][] lastTokens; void resetButtons() { CharSequence selectText = select.getText(); @@ -872,13 +874,14 @@ public void orderCards(int[] cards) { * Display the numbers of pile sizes for the card piles on the 'table' * @param supplySizes Sizes of piles * @param embargos number of embargos + * @param tokens */ - 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); + public void setSupplySizes(int[] supplySizes, int[] embargos, int[][][] tokens) { + moneyPile.updateCounts(supplySizes, embargos, tokens); + vpPile.updateCounts(supplySizes, embargos, tokens); + supplyPile.updateCounts(supplySizes, embargos, tokens); + prizePile.updateCounts(supplySizes, embargos, tokens); + nonSupplyPile.updateCounts(supplySizes, embargos, tokens); } /** @@ -942,7 +945,7 @@ public void finalStatus(GameStatus gs) { ViewGroup.LayoutParams.WRAP_CONTENT); FinalView fv = new FinalView(top, this, gs.realNames[gs.whoseTurn], gs.turnCounts[gs.whoseTurn], - gs.embargos, + gs.embargos, gs.tokens, gs.numCards[gs.whoseTurn], gs.supplySizes, gs.handSizes[gs.whoseTurn], won); fv.setLayoutParams(lp); @@ -953,7 +956,7 @@ public void finalStatus(GameStatus gs) { void uncheckAllShowCardsButtons() { for (ToggleButton t : showCardsButtons) t.setChecked(false); - setSupplySizes(this.lastSupplySizes, this.lastEmbargos); + setSupplySizes(this.lastSupplySizes, this.lastEmbargos, this.lastTokens); } /** @@ -985,7 +988,7 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { /*print ruins and not abandoned mine*/ supplyPile.updateCardName(gs.ruinsID, Cards.virtualRuins, -1, false); supplyPile.updateCardName(gs.knightsID, Cards.virtualKnight, -1, false); - setSupplySizes(this.lastSupplySizes, this.lastEmbargos); + setSupplySizes(this.lastSupplySizes, this.lastEmbargos, this.lastTokens); HapticFeedback.vibrate(getContext(),AlertType.FINAL); finalStatus(gs); @@ -1068,11 +1071,12 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { this.lastSupplySizes = gs.supplySizes; this.lastEmbargos = gs.embargos; + this.lastTokens = gs.tokens; costs = gs.costs; supplyPile.updateCardName(gs.ruinsID, gs.ruinsTopCard, -1, false); supplyPile.updateCardName(gs.knightsID, gs.knightsTopCard, gs.knightsTopCardCost, gs.knightsTopCardIsVictory); - setSupplySizes(gs.supplySizes, gs.embargos); + setSupplySizes(gs.supplySizes, gs.embargos, gs.tokens); setCardCosts(top.findViewById(android.R.id.content)); } diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 49ea85b3e..1a2731f33 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -218,6 +218,18 @@ public static String getStatusText(Event event, Object[] extras) { // The first part of the text tells us what kind of event we're dealing with. if (event.gameEventType == GameEvent.Type.Embargo) { statusText += getString(R.string.Embargo); + } else if (event.gameEventType == GameEvent.Type.PlusOneCardTokenMoved) { + statusText += getString(R.string.PlusOneCardTokenMoved); + } else if (event.gameEventType == GameEvent.Type.PlusOneActionTokenMoved) { + statusText += getString(R.string.PlusOneActionTokenMoved); + } else if (event.gameEventType == GameEvent.Type.PlusOneBuyTokenMoved) { + statusText += getString(R.string.PlusOneBuyTokenMoved); + } else if (event.gameEventType == GameEvent.Type.PlusOneCoinTokenMoved) { + statusText += getString(R.string.PlusOneCoinTokenMoved); + } else if (event.gameEventType == GameEvent.Type.MinusTwoCostTokenMoved) { + statusText += getString(R.string.MinusTwoCostTokenMoved); + } else if (event.gameEventType == GameEvent.Type.TrashingTokenMoved) { + statusText += getString(R.string.TrashingTokenMoved); } else if (event.gameEventType == GameEvent.Type.GameStarting) { statusText += getString(R.string.GameStarting); } else if (event.gameEventType == GameEvent.Type.GameOver) { @@ -1012,6 +1024,8 @@ else if (sco.minCost == sco.maxCost) { } else { if (sco.isAttack) { selectString = Strings.format(R.string.select_from_table_attack, header); + } if (sco.isAction) { + selectString = Strings.format(R.string.select_from_table_action, header); } else { selectString = Strings.format(R.string.select_from_table, header); } @@ -1167,11 +1181,14 @@ private static void initActionStrings() { getCardName(Cards.raze), getCardName(Cards.storyteller), /*Adventures Events*/ - getCardName(Cards.alms) + getCardName(Cards.alms), + getCardName(Cards.seaway) + )); actionStringMap = new HashMap(); actionStringMap.put(getCardName(Cards.bureaucrat), getString(R.string.bureaucrat_part)); actionStringMap.put(getCardName(Cards.bandOfMisfits), getString(R.string.part_play)); + actionStringMap.put(getCardName(Cards.ferry), getString(R.string.part_move_token_minus_2_cost)); actionStringMap.put(getCardName(Cards.courtyard), Strings.format(R.string.courtyard_part_top_of_deck, getCardName(Cards.courtyard))); @@ -1183,8 +1200,10 @@ private static void initActionStrings() { actionStringMap.put(getCardName(Cards.haven), getString(R.string.haven_part)); actionStringMap.put(getCardName(Cards.gear), getString(R.string.gear_part)); actionStringMap.put(getCardName(Cards.island), getString(R.string.island_part)); + actionStringMap.put(getCardName(Cards.pathfinding), getString(R.string.part_move_token_plus_one_card)); actionStringMap.put(getCardName(Cards.prince), getString(R.string.prince_part)); actionStringMap.put(getCardName(Cards.kingsCourt), getString(R.string.kings_court_part)); + actionStringMap.put(getCardName(Cards.lostArts), getString(R.string.part_move_token_plus_one_action)); actionStringMap.put(getCardName(Cards.mandarin), getString(R.string.mandarin_part)); actionStringMap.put(getCardName(Cards.margrave), getString(R.string.margrave_part)); actionStringMap.put(getCardName(Cards.militia), getString(R.string.militia_part)); @@ -1194,6 +1213,7 @@ private static void initActionStrings() { actionStringMap.put(getCardName(Cards.throneRoom), getString(R.string.throne_room_part)); actionStringMap.put(getCardName(Cards.disciple), getString(R.string.throne_room_part)); /*frr18 todo*/ actionStringMap.put(getCardName(Cards.tournament), getString(R.string.select_prize)); + actionStringMap.put(getCardName(Cards.training), getString(R.string.part_move_token_plus_one_coin)); actionStringMap.put(getCardName(Cards.university), getString(R.string.university_part)); actionStringMap.put(getCardName(Cards.urchin), getString(R.string.urchin_keep)); } @@ -1287,6 +1307,12 @@ public static String getActionCardText(SelectCardOptions sco) { } else { return getString(R.string.taxman_part); } + } else if (cardName.equals(getCardName(Cards.plan))) { + if (sco.actionType == ActionType.TRASH) { + return getActionString(sco); + } else { + return getString(R.string.part_move_token_trashing); + } } throw new RuntimeException("Found a card in getActionCardText that I don't know how to handle yet"); } diff --git a/androminion/src/com/mehtank/androminion/util/CardGroup.java b/androminion/src/com/mehtank/androminion/util/CardGroup.java index 19aad9d08..c9026d026 100644 --- a/androminion/src/com/mehtank/androminion/util/CardGroup.java +++ b/androminion/src/com/mehtank/androminion/util/CardGroup.java @@ -31,10 +31,12 @@ public class CardGroup extends BaseAdapter { // fix bug that lets item countLeft jump around int[] supplySizes = null; int[] embargos = null; + int[][][] tokens = null; - public void updateCounts(int[] supplySizes, int[] embargos) { + public void updateCounts(int[] supplySizes, int[] embargos, int[][][] tokens) { this.supplySizes = supplySizes; this.embargos = embargos; + this.tokens = tokens; notifyDataSetChanged(); } @@ -108,6 +110,8 @@ public View getView(int pos, View origView, ViewGroup parent) { cv.setCountLeft(supplySizes[cs.c.id]); if (embargos != null) cv.setEmbargos(embargos[cs.c.id]); + if (tokens != null) + cv.setTokens(tokens[cs.c.id]); } catch (ArrayIndexOutOfBoundsException e) { // TODO See why this is happening? Log.w(TAG, "exception", e); diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index 38a9f73e7..d20224af1 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -47,10 +47,16 @@ public enum Type { DeckPutIntoDiscardPile, // Deck put into discard pile TurnJourneyTokenFaceUp, // journey token turned face up TurnJourneyTokenFaceDown, // journey token turned face down - MinusOneCoinTokenOn, // journey token turned face up - MinusOneCoinTokenOff, // journey token turned face down - MinusOneCardTokenOn, // journey token turned face up - MinusOneCardTokenOff, // journey token turned face down + MinusOneCoinTokenOn, // -1 Coin token taken by player + MinusOneCoinTokenOff, // -1 Coin token removed by player + MinusOneCardTokenOn, // -1 Card token put on deck by player + MinusOneCardTokenOff, // -1 Card token drawn from deck by player + PlusOneCardTokenMoved, // +1 Card token moved to supply pile + PlusOneActionTokenMoved, // +1 Action token moved to supply pile + PlusOneBuyTokenMoved, // +1 Buy token moved to supply pile + PlusOneCoinTokenMoved, // +1 Coin token moved to supply pile + MinusTwoCostTokenMoved, // -2 Cost Token moved to supply pile + TrashingTokenMoved, // Trashing token moved to supply pile } public Type type; diff --git a/vdom/src/com/vdom/comms/GameStatus.java b/vdom/src/com/vdom/comms/GameStatus.java index 798bed63b..e80c3fe4d 100644 --- a/vdom/src/com/vdom/comms/GameStatus.java +++ b/vdom/src/com/vdom/comms/GameStatus.java @@ -5,9 +5,10 @@ import com.vdom.api.Card; public class GameStatus implements Serializable { - private static final long serialVersionUID = -5928579898003313213L; - - public int whoseTurn; + + private static final long serialVersionUID = -8819195521987453596L; + + public int whoseTurn; public String name; public String[] realNames; public boolean isFinal; @@ -25,6 +26,7 @@ public class GameStatus implements Serializable { public int[] turnStatus; public int[] supplySizes; public int[] embargos; + public int[][][] tokens; public int[] costs; public int[] deckSizes; public int[] handSizes; @@ -61,6 +63,7 @@ public class GameStatus implements Serializable { public GameStatus setTurnStatus(int[] is) {turnStatus = is; return this;}; public GameStatus setSupplySizes(int[] is) {supplySizes = is; return this;}; public GameStatus setEmbargos(int[] is) {embargos = is; return this;}; + public GameStatus setTokens(int[][][] is) {tokens = is; return this;}; public GameStatus setCosts(int[] is) {costs = is; return this;}; public GameStatus setDeckSizes(int[] is) {deckSizes = is; return this;}; public GameStatus setHandSizes(int[] is) {handSizes = is; return this;}; diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index d68a2a4c8..9e6cc1fa3 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -238,13 +238,22 @@ public void play(Game game, MoveContext context, boolean fromHand) { event.card = this; event.newCard = newCard; game.broadcastEvent(event); - + // playing an action if (this == actualCard) context.actionsPlayedSoFar++; if (context.freeActionInEffect == 0) { context.actions--; } + + if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneAction)) + context.actions += 1; + if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneBuy)) + context.buys += addBuys; + if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCoin)) + context.addCoins(1); + if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCard)) + game.drawToHand(currentPlayer, actualCard); context.actions += addActions; context.buys += addBuys; diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index e91b16b55..5899c30b0 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3306,6 +3306,26 @@ public Card alms_cardToObtain(MoveContext context) { public Card[] bonfire_cardsToTrash(MoveContext context) { return pickOutCards(context.getPlayer().playedCards, 2, getTrashCards()); } + + @Override + public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { + return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + } + + @Override + public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { + return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + } + + @Override + public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { + return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + } + + @Override + public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { + return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + } @Override public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { @@ -3314,5 +3334,19 @@ public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { cl.add(c); return lowestCard(context, cl, true); } - + + @Override + public ActionCard seaway_cardToObtain(MoveContext context) { + return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); + } + + @Override + public ActionCard training_actionCardPileToHaveToken(MoveContext context) { + return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + } + + @Override + public Card trashingToken_cardToTrash(MoveContext context) { + return pickOutCard(context.getPlayer().getHand(), getTrashCards()); + } } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index bd680a4c9..b6a7a68b1 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -234,6 +234,7 @@ public int getCost(MoveContext context, boolean buyPhase) { costModifier -= context.countCardsInNextTurn(Cards.bridgeTroll); costModifier -= 2 * context.countCardsInPlay(Cards.princess); costModifier -= (buyPhase && this.equals(Cards.peddler)) ? (2 * context.countActionCardsInPlayThisTurn()) : 0; + costModifier -= (context.game.isPlayerSupplyTokenOnPile(this, context.game.getCurrentPlayer(), PlayerSupplyToken.MinusTwoCost)) ? 2 : 0; //costModifier -= (this.isKnight ? (cost - game. (2 * context.countCardsInPlay(Cards.quarry)) : 0; return Math.max(0, cost + costModifier + context.cardCostModifier/*bridge*/); diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 24665fabb..d58ec3023 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -736,7 +736,7 @@ public enum Type { eventsCards.add(bonfire = new EventCardImpl.Builder(Cards.Type.Bonfire , 3).isEvent().description("Trash up to 2 cards you have in play.").expansion("Adventures").build()); eventsCards.add(borrow = new EventCardImpl.Builder(Cards.Type.Borrow , 0).addBuys(1).isEvent().description("Once per turn: If your -1 Card token isn't on your deck, put it there and +1 Coin.").expansion("Adventures").build()); eventsCards.add(expedition = new EventCardImpl.Builder(Cards.Type.Expedition , 3).isEvent().description("Draw 2 extra cards for your next hand.").expansion("Adventures").build()); - eventsCards.add(ferry = new EventCardImpl.Builder(Cards.Type.Ferry , 3).isEvent().description("Move your -2 Coins cost token to an Action Supply pile (cards from that pile cost 2 Coins less on your turns, but not less than 0 Coins).").expansion("Adventures").build()); + eventsCards.add(ferry = new EventCardImpl.Builder(Cards.Type.Ferry , 3).isEvent().description("Move your -2 cost token to an Action Supply pile (cards from that pile cost 2 Coins less on your turns, but not less than 0 Coins).").expansion("Adventures").build()); eventsCards.add(inheritance = new EventCardImpl.Builder(Cards.Type.Inheritance , 7).isEvent().description("Once per game: Set aside a non-Victory Action card from the Supply costing up to 4 Coins. Move your Estate token to it (your Estates gain the abilities and types of that card).").expansion("Adventures").build()); eventsCards.add(lostArts = new EventCardImpl.Builder(Cards.Type.LostArts , 6).isEvent().description("Move your +1 Action token to an Action Supply pile (when you play a card from that pile, you first get +1 Action).").expansion("Adventures").build()); eventsCards.add(mission = new EventCardImpl.Builder(Cards.Type.Mission , 4).isEvent().description("Once per turn: If the previous turn wasn't yours, take another turn after this one, in which you can't buy cards.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index bab6f47d4..0f39f9968 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -2,6 +2,7 @@ import java.util.ArrayList; +import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.EventCard; import com.vdom.api.TreasureCard; @@ -66,6 +67,18 @@ public void isBuying(MoveContext context) { case Expedition: context.totalExpeditionBoughtThisTurn += 2; break; + case Ferry: + ferry(context); + break; + case LostArts: + lostArts(context); + break; + case Pathfinding: + pathfinding(context); + break; + case Plan: + plan(context); + break; case Raid: raid(context); break; @@ -75,10 +88,32 @@ public void isBuying(MoveContext context) { case ScoutingParty: scoutingParty(context); break; + case Seaway: + seaway(context); + break; + case Training: + training(context); + break; default: break; } } + + private void placeToken(MoveContext context, ActionCard card, PlayerSupplyToken token) { + if (card == null) { + Card[] cards = context.game.getActionsInGame(); + if (cards.length != 0) { + Util.playerError(context.getPlayer(), getName() + " error: did not pick a valid pile, ignoring."); + } + return; + } + if (!context.game.cardInGame(card) || + !Cards.isSupplyCard(card)) { + Util.playerError(context.getPlayer(), getName() + " error: Invalid pile chosen, ignoring"); + } + + context.game.movePlayerSupplyToken(card, context.getPlayer(), token); + } public void alms(MoveContext context) { boolean noTreasureCard = true; @@ -124,9 +159,29 @@ protected void borrow(MoveContext context) { context.addCoins(1); } context.cantBuy.add(this); //once per turn - } + } + + private void ferry(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.ferry_actionCardPileToHaveToken(context); + placeToken(context, card, PlayerSupplyToken.MinusTwoCost); + } + + private void lostArts(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.lostArts_actionCardPileToHaveToken(context); + placeToken(context, card, PlayerSupplyToken.PlusOneAction); + } + + private void pathfinding(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.pathfinding_actionCardPileToHaveToken(context); + placeToken(context, card, PlayerSupplyToken.PlusOneCard); + } - protected void raid(MoveContext context) { + private void plan(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.plan_actionCardPileToHaveToken(context); + placeToken(context, card, PlayerSupplyToken.Trashing); + } + + protected void raid(MoveContext context) { for(Card card : context.player.playedCards) { if (card.equals(Cards.silver)) { context.player.gainNewCard(Cards.silver, this, context); @@ -138,7 +193,7 @@ protected void raid(MoveContext context) { targetPlayer.setMinusOneCardToken(true, targetContext); } } - } + } private void save(MoveContext context) { Card card = context.player.controlPlayer.haven_cardToSetAside(context); /*frr18 todo right name*/ @@ -225,6 +280,21 @@ private void scoutingParty(MoveContext context) { } } + private void seaway(MoveContext context) { + ActionCard card = context.player.controlPlayer.seaway_cardToObtain(context); + if (card != null) { + if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card)) { + Card gainedCard = context.player.gainNewCard(card, this.controlCard, context); + if (card.equals(gainedCard)) + placeToken(context, card, PlayerSupplyToken.PlusOneBuy); + } + } + + } + private void training(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.training_actionCardPileToHaveToken(context); + placeToken(context, card, PlayerSupplyToken.PlusOneCoin); + } } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 6b7d7e988..9041c0c82 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -21,6 +21,7 @@ import com.vdom.api.FrameworkEvent; import com.vdom.api.FrameworkEventHelper; import com.vdom.api.GameEvent; +import com.vdom.api.GameEvent.Type; import com.vdom.api.GameEventListener; import com.vdom.api.GameType; import com.vdom.api.TreasureCard; @@ -95,6 +96,7 @@ public class Game { public static Random rand = new Random(System.currentTimeMillis()); public HashMap piles = new HashMap(); public HashMap embargos = new HashMap(); + private HashMap>> playerSupplyTokens = new HashMap>>(); public ArrayList trashPile = new ArrayList(); public ArrayList possessedTrashPile = new ArrayList(); public ArrayList possessedBoughtPile = new ArrayList(); @@ -1340,8 +1342,20 @@ Card playBuy(MoveContext context, Card buy) { } buy.isBuying(context); - + if(!buy.isEvent()) { + if (player.getHand().size() > 0 && isPlayerSupplyTokenOnPile(buy, player, PlayerSupplyToken.Trashing)) { + Card cardToTrash = player.controlPlayer.trashingToken_cardToTrash((MoveContext) context); + if (cardToTrash != null) { + if (!player.getHand().contains(cardToTrash)) { + Util.playerError(player, "Trashing token error, invalid card to trash, ignoring."); + } else { + player.hand.remove(cardToTrash); + player.trash(cardToTrash, null, context); + } + } + } + /*frr18 todo defense */ for (int i=0; i < swampHagAttacks(player); i++) { player.gainNewCard(Cards.curse, Cards.swampHag, context); @@ -1689,7 +1703,7 @@ protected void initPlayers(int numPlayers, boolean isRandom) throws ExitExceptio // Interactive player needs this called once for each player on startup so internal counts work properly. players[i].getPlayerName(); - + MoveContext context = new MoveContext(this, players[i]); players[i].newGame(context); players[i].initCards(); @@ -1821,6 +1835,7 @@ protected void initPlayerCards() { protected void initCards() { piles.clear(); embargos.clear(); + playerSupplyTokens.clear(); trashPile.clear(); blackMarketPile.clear(); blackMarketPileShuffled.clear(); @@ -2626,7 +2641,54 @@ public int getEmbargos(Card card) { return (count == null) ? 0 : count; } - // Only is valid for cards in play... + public List getPlayerSupplyTokens(Card card, Player player) { + card = card.getTemplateCard(); + if (player == null || !playerSupplyTokens.containsKey(card.getName())) + return new ArrayList(); + + if (!playerSupplyTokens.get(card.getName()).containsKey(player)) { + playerSupplyTokens.get(card.getName()).put(player, new ArrayList()); + } + return playerSupplyTokens.get(card.getName()).get(player); + } + + public boolean isPlayerSupplyTokenOnPile(Card card, Player player, PlayerSupplyToken token) { + return getPlayerSupplyTokens(card, player).contains(token); + } + + public void movePlayerSupplyToken(Card card, Player player, PlayerSupplyToken token) { + removePlayerSupplyToken(player, token); + getPlayerSupplyTokens(card, player).add(token); + + MoveContext context = new MoveContext(this, player); + GameEvent.Type eventType = null; + if (token == PlayerSupplyToken.PlusOneCard) { + eventType = Type.PlusOneCardTokenMoved; + } else if (token == PlayerSupplyToken.PlusOneAction) { + eventType = Type.PlusOneActionTokenMoved; + } else if (token == PlayerSupplyToken.PlusOneBuy) { + eventType = Type.PlusOneBuyTokenMoved; + } else if (token == PlayerSupplyToken.PlusOneCoin) { + eventType = Type.PlusOneCoinTokenMoved; + } else if (token == PlayerSupplyToken.MinusTwoCost) { + eventType = Type.MinusTwoCostTokenMoved; + } else if (token == PlayerSupplyToken.Trashing) { + eventType = Type.TrashingTokenMoved; + } + GameEvent event = new GameEvent(eventType, context); + event.card = card; + broadcastEvent(event); + } + + private void removePlayerSupplyToken(Player player, PlayerSupplyToken token) { + for (String cardName : playerSupplyTokens.keySet()) { + if (playerSupplyTokens.get(cardName).containsKey(player)) { + playerSupplyTokens.get(cardName).get(player).remove(token); + } + } + } + + // Only is valid for cards in play... // protected Card readCard(String name) { // AbstractCardPile pile = piles.get(name); // if (pile == null || pile.getCount() <= 0) { @@ -2817,6 +2879,9 @@ protected AbstractCardPile addPile(Card card, int count, boolean isSupply, boole } piles.put(card.getName(), pile); + + playerSupplyTokens.put(card.getName(), new HashMap>()); + return pile; } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 93796e8ed..e53ec3cc1 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2696,6 +2696,46 @@ public Card[] bonfire_cardsToTrash(MoveContext context) { .setCardResponsible(Cards.bonfire).setActionType(ActionType.TRASH); return getFromPlayed(context, sco); } + + @Override + public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_ferry_actionCardPileToHaveToken(context)) { + return super.ferry_actionCardPileToHaveToken(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().setCardResponsible(Cards.ferry); + return (ActionCard) getFromTable(context, sco); + } + + @Override + public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_lostArts_actionCardPileToHaveToken(context)) { + return super.lostArts_actionCardPileToHaveToken(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().setCardResponsible(Cards.lostArts); + return (ActionCard) getFromTable(context, sco); + } + + @Override + public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_pathfinding_actionCardPileToHaveToken(context)) { + return super.pathfinding_actionCardPileToHaveToken(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().setCardResponsible(Cards.pathfinding); + return (ActionCard) getFromTable(context, sco); + } + + @Override + public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_plan_actionCardPileToHaveToken(context)) { + return super.plan_actionCardPileToHaveToken(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().setCardResponsible(Cards.plan); + return (ActionCard) getFromTable(context, sco); + } @Override public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { @@ -2709,6 +2749,36 @@ public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { } return cards[selectOption(context, Cards.scoutingParty, options)]; } + + @Override + public ActionCard seaway_cardToObtain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_seaway_cardToObtain(context)) { + return super.seaway_cardToObtain(context); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) + .setCardResponsible(Cards.seaway).isAction().setActionType(ActionType.GAIN); + return (ActionCard) getFromTable(context, sco); + } + @Override + public ActionCard training_actionCardPileToHaveToken(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_training_actionCardPileToHaveToken(context)) { + return super.training_actionCardPileToHaveToken(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().setCardResponsible(Cards.training); + return (ActionCard) getFromTable(context, sco); + } + + @Override + public Card trashingToken_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_trashingToken_cardToTrash(context)) { + return super.trashingToken_cardToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setPassable() + .setPickType(PickType.TRASH).setActionType(ActionType.TRASH) + .setCardResponsible(Cards.plan); + return getCardFromHand(context, sco); + } } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 93fda8dad..4dd0690fc 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1715,7 +1715,14 @@ public ArrayList getActionsInHand() { public abstract Card alms_cardToObtain(MoveContext context); public abstract Card[] bonfire_cardsToTrash(MoveContext context); + public abstract ActionCard ferry_actionCardPileToHaveToken(MoveContext context); + public abstract ActionCard lostArts_actionCardPileToHaveToken(MoveContext context); + public abstract ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context); + public abstract ActionCard plan_actionCardPileToHaveToken(MoveContext context); public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); + public abstract ActionCard seaway_cardToObtain(MoveContext context); + public abstract ActionCard training_actionCardPileToHaveToken(MoveContext context); + public abstract Card trashingToken_cardToTrash(MoveContext context); // //////////////////////////////////////////// // Card interactions - Promotional Cards diff --git a/vdom/src/com/vdom/core/PlayerSupplyToken.java b/vdom/src/com/vdom/core/PlayerSupplyToken.java new file mode 100644 index 000000000..a5bdc0030 --- /dev/null +++ b/vdom/src/com/vdom/core/PlayerSupplyToken.java @@ -0,0 +1,23 @@ +package com.vdom.core; + +public enum PlayerSupplyToken { + PlusOneCard(1), PlusOneAction(2), PlusOneBuy(3), PlusOneCoin(4), MinusTwoCost(5), Trashing(6); + + private int id; + + private PlayerSupplyToken(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public static PlayerSupplyToken getById(int id) { + for (PlayerSupplyToken token : PlayerSupplyToken.values()) { + if (token.id == id) + return token; + } + return null; + } +} diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index cf882cd5c..498831b37 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -859,9 +859,37 @@ public boolean shouldAutoPlay_cleanup_wineMerchantToDiscard(MoveContext context) public boolean shouldAutoPlay_alms_cardToObtain(MoveContext context) { return false; } + + public boolean shouldAutoPlay_ferry_actionCardPileToHaveToken(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_lostArts_actionCardPileToHaveToken(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_pathfinding_actionCardPileToHaveToken(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_plan_actionCardPileToHaveToken(MoveContext context) { + return false; + } public boolean shouldAutoPlay_scoutingParty_cardToDiscard(MoveContext context) { return false; } + + public boolean shouldAutoPlay_seaway_cardToObtain(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_training_actionCardPileToHaveToken(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_trashingToken_cardToTrash(MoveContext context) { + return true; + } } diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 2e1e41c97..dc210c1cb 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -305,6 +305,7 @@ public Event fullStatusPacket(MoveContext context, Player player, boolean isFina int[] supplySizes = new int[cardsInPlay.size()]; int[] embargos = new int[cardsInPlay.size()]; + int[][][] tokens = new int[cardsInPlay.size()][][]; int[] costs = new int[cardsInPlay.size()]; int i_virtualRuins = -1; @@ -339,6 +340,7 @@ else if (cardsInPlay.get(i).isKnight()) } } embargos[i] = context.getEmbargos(intToCard(i)); + costs[i] = intToCard(i).getCost(context); } if (isFinal) @@ -396,6 +398,21 @@ else if (cardsInPlay.get(i).isKnight()) minusOneCardTokenOn[i] = p.getMinusOneCardToken(); realNames[i] = p.getPlayerName(false); } + + for (int i = 0; i < cardsInPlay.size(); i++) { + Card card = cardsInPlay.get(i); + int[][] playersForCard = new int[numPlayers][]; + for (int j = 0; j < numPlayers; j++) { + Player p = allPlayers.get(j); + List playerTokensList = context.game.getPlayerSupplyTokens(card, p); + int[] playerTokensOnCard = new int[playerTokensList.size()]; + for (int k = 0; k < playerTokensOnCard.length; ++k) { + playerTokensOnCard[k] = playerTokensList.get(k).getId(); + } + playersForCard[j] = playerTokensOnCard; + } + tokens[i] = playersForCard; + } GameStatus gs = new GameStatus(); @@ -416,6 +433,7 @@ else if (cardsInPlay.get(i).isKnight()) .setTurnCounts(turnCounts) .setSupplySizes(supplySizes) .setEmbargos(embargos) + .setTokens(tokens) .setCosts(costs) .setHand(cardArrToIntArr(Game.sortCards ? shownHand.sort(new Util.CardHandComparator()) : shownHand.toArray())) .setPlayedCards(playedArray) From 5829f3fd799f6a806f5c7a06d775fea57ab1be7c Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 2 Jan 2016 12:05:58 -0700 Subject: [PATCH 019/141] Adding framework for calling cards from Tavern mat. Implmementing Adventures cards: Duplicate, Ratcatcher, Guide, Teacher, Transmogrify, Royal Carriage, Coin of the Realm Can't yet call any cards except Duplicate. --- androminion/res/values/colors.xml | 2 +- androminion/res/values/strings-cards.xml | 2 +- androminion/res/values/strings-server.xml | 11 + .../com/mehtank/androminion/ui/GameTable.java | 15 +- .../com/mehtank/androminion/ui/Strings.java | 48 +++- vdom/src/com/vdom/api/GameEvent.java | 2 + .../src/com/vdom/comms/SelectCardOptions.java | 16 +- vdom/src/com/vdom/core/ActionCardImpl.java | 6 + vdom/src/com/vdom/core/BasePlayer.java | 156 ++++++++++- .../com/vdom/core/CallableActionCardImpl.java | 263 ++++++++++++++++++ vdom/src/com/vdom/core/CallableCard.java | 19 ++ .../vdom/core/CallableTreasureCardImpl.java | 146 ++++++++++ vdom/src/com/vdom/core/CardImpl.java | 17 ++ vdom/src/com/vdom/core/Cards.java | 14 +- vdom/src/com/vdom/core/EventCardImpl.java | 16 -- vdom/src/com/vdom/core/Game.java | 39 ++- vdom/src/com/vdom/core/IndirectPlayer.java | 100 ++++++- vdom/src/com/vdom/core/Player.java | 27 ++ vdom/src/com/vdom/core/QuickPlayPlayer.java | 25 ++ vdom/src/com/vdom/core/TreasureCardImpl.java | 33 ++- 20 files changed, 880 insertions(+), 77 deletions(-) create mode 100644 vdom/src/com/vdom/core/CallableActionCardImpl.java create mode 100644 vdom/src/com/vdom/core/CallableCard.java create mode 100644 vdom/src/com/vdom/core/CallableTreasureCardImpl.java diff --git a/androminion/res/values/colors.xml b/androminion/res/values/colors.xml index e86c48f72..1bbe05732 100644 --- a/androminion/res/values/colors.xml +++ b/androminion/res/values/colors.xml @@ -18,7 +18,7 @@ #9400D3 #806F49 #B0AFA7 - #E6DEC8 + #DDC492 #d9562b #508db9 diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index 5cfc17cca..9780cd7ef 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -542,7 +542,7 @@ Swamp Hag Until your next turn, when any other player buys a card, he gains a Curse. Teacher - Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus). + Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 Coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus). Transmogrify Put this on your Tavern mat. - At the start of your turn, you may call this, to trash a card from your hand, gain a card costing up to 1 Coin more than it, and put that card into your hand. TreasureHunter diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index a42dc0a31..688a157af 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -145,6 +145,8 @@ Card added to hand Card removed from hand Card put on tavern mat + Calling + Called Card set aside (prince) Card set aside (Haven) Card set aside (Gear) @@ -156,6 +158,11 @@ -1 coin token removed -1 card token put onto deck -1 card token removed + + +1 Card token + +1 Action token + +1 Buy token + +1 Coin token use for money @@ -194,6 +201,8 @@ Select card to smuggle + Select token to move + put on top of your deck [%1$s] discard for +1 Action @@ -402,4 +411,6 @@ Exchange it for %1$s Discard from Tavern Select number of Wine Merchants, to discard from Tavern + + Gaining %1$s. Call card: diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 14177c301..3f6516cd4 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -67,6 +67,7 @@ public PlayerAdapter getPlayerAdapter() { LinearLayout turnView; View myCardView; private static int[] costs = {}; + private static int[][][] tokens = {}; TextView actionText; LinearLayout deckStatus; @@ -494,7 +495,7 @@ else if (sco.fromTable) { if (parent != prizePile) return false; } - return sco.checkValid(c, getCardCost(c)); + return sco.checkValid(c, getCardCost(c), getHasTokensForPlayer(c, sco.noTokensForPlayer)); } /** @@ -1073,6 +1074,7 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { this.lastEmbargos = gs.embargos; this.lastTokens = gs.tokens; costs = gs.costs; + tokens = gs.tokens; supplyPile.updateCardName(gs.ruinsID, gs.ruinsTopCard, -1, false); supplyPile.updateCardName(gs.knightsID, gs.knightsTopCard, gs.knightsTopCardCost, gs.knightsTopCardIsVictory); @@ -1087,6 +1089,17 @@ static int getCardCost(MyCard c) { return costs[c.id]; return c.cost; } + + static boolean getHasTokensForPlayer(MyCard c, int playerIndex) { + if (playerIndex == -1) + return false; + if (tokens == null || tokens.length == 0) + return false; + if (c.id >= tokens.length) return false; + int[][] cardTokens = tokens[c.id]; + if (playerIndex >= cardTokens.length) return false; + return tokens[c.id][playerIndex].length > 0; + } private void setCardCosts(View v) { if (v instanceof CardView) { diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 1a2731f33..4ec52596b 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -25,6 +25,7 @@ import com.vdom.comms.SelectCardOptions.ActionType; import com.vdom.comms.SelectCardOptions.PickType; import com.vdom.core.Cards; +import com.vdom.core.IndirectPlayer; import com.vdom.core.Player.AmuletOption; import com.vdom.core.Player.CountFirstOption; import com.vdom.core.Player.CountSecondOption; @@ -44,6 +45,7 @@ import com.vdom.core.Player.TournamentOption; import com.vdom.core.Player.TrustySteedOption; import com.vdom.core.Player.WatchTowerOption; +import com.vdom.core.PlayerSupplyToken; public class Strings { @@ -277,6 +279,10 @@ public static String getStatusText(Event event, Object[] extras) { statusText += getString(R.string.CardSetAsideGear); } else if (event.gameEventType == GameEvent.Type.CardSetAsideOnTavernMat) { statusText += getString(R.string.CardSetAsideOnTavernMat); + } else if (event.gameEventType == GameEvent.Type.CallingCard) { + statusText += getString(R.string.CallingCard); + } else if (event.gameEventType == GameEvent.Type.CalledCard) { + statusText += getString(R.string.CalledCard); } else if (event.gameEventType == GameEvent.Type.CardSetAsideOnIslandMat) { statusText += getString(R.string.CardSetAsideOnIslandMat); } else if (event.gameEventType == GameEvent.Type.DeckPutIntoDiscardPile) { @@ -500,17 +506,19 @@ private static int getOptionStartIndex(Card card, Object[] options) { // strings. if (options[0] instanceof String) { String optionString = (String) options[0]; - if (optionString.equals("REACTION")) { + if (optionString.equals(IndirectPlayer.OPTION_REACTION)) { return 1; - } else if (optionString.equals("PUTBACK")) { + } else if (optionString.equals(IndirectPlayer.OPTION_PUTBACK)) { return 1; - } else if (optionString.equals("GUILDCOINS")) { + } else if (optionString.equals(IndirectPlayer.OPTION_SPEND_GUILD_COINS)) { return 1; - } else if (optionString.equals("OVERPAY")) { + } else if (optionString.equals(IndirectPlayer.OPTION_OVERPAY)) { return 1; - } else if (optionString.equals("OVERPAYP")) { + } else if (optionString.equals(IndirectPlayer.OPTION_OVERPAY_POTION)) { return 1; - } + } else if (optionString.equals(IndirectPlayer.OPTION_CALL_WHEN_GAIN)) { + return 1; + } } if (card == null) return 0; @@ -542,17 +550,19 @@ private static int getOptionStartIndex(Card card, Object[] options) { } public static String getSelectOptionHeader(Card card, Object[] extras) { - if (extras[0] instanceof String && ((String)extras[0]).equals("PUTBACK")) { + if (extras[0] instanceof String && ((String)extras[0]).equals(IndirectPlayer.OPTION_PUTBACK)) { return getString(R.string.putback_query); - } else if (extras[0] instanceof String && ((String)extras[0]).equals("REACTION")) { + } else if (extras[0] instanceof String && ((String)extras[0]).equals(IndirectPlayer.OPTION_REACTION)) { return getString(R.string.reaction_query) + " [" + getCardName(card) + "]"; - } else if (extras[0] instanceof String && ((String)extras[0]).equals("GUILDCOINS")) { + } else if (extras[0] instanceof String && ((String)extras[0]).equals(IndirectPlayer.OPTION_SPEND_GUILD_COINS)) { return getString(R.string.spend_guilds_coin_tokens); - } else if (extras[0] instanceof String && ((String)extras[0]).equals("OVERPAY")) { + } else if (extras[0] instanceof String && ((String)extras[0]).equals(IndirectPlayer.OPTION_OVERPAY)) { return getString(R.string.buy_overpay); - } else if (extras[0] instanceof String && ((String)extras[0]).equals("OVERPAYP")) { + } else if (extras[0] instanceof String && ((String)extras[0]).equals(IndirectPlayer.OPTION_OVERPAY_POTION)) { return getString(R.string.buy_overpay_by_potions); - } + } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_CALL_WHEN_GAIN)) { + return format(R.string.call_when_gain_query, getCardName(card)); + } String cardName = getCardName(card); if (cardName.equals(getCardName(Cards.advisor))) { return getActionString(ActionType.OPPONENTDISCARD, card, (String) extras[0]); @@ -596,6 +606,8 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { return getString(R.string.scheme_query); } else if (cardName.equals(getCardName(Cards.smugglers))) { return getString(R.string.smuggle_query); + } else if (cardName.equals(getCardName(Cards.teacher))) { + return getString(R.string.teacher_query); } else if (cardName.equals(getCardName(Cards.thief))) { if (extras[0] == null) { // In this case we're gaining treasures that have been trashed. @@ -744,6 +756,16 @@ public static String getOptionText(Object option, Object[] extras) { } else if (option == PawnOption.AddGold) { return getString(R.string.pawn_four); } + } else if (option instanceof PlayerSupplyToken) { + if (option == PlayerSupplyToken.PlusOneCard) { + return getString(R.string.plus_one_card_token); + } else if (option == PlayerSupplyToken.PlusOneAction) { + return getString(R.string.plus_one_action_token); + } else if (option == PlayerSupplyToken.PlusOneBuy) { + return getString(R.string.plus_one_buy_token); + } else if (option == PlayerSupplyToken.PlusOneCoin) { + return getString(R.string.plus_one_coin_token); + } } else if (option instanceof DoctorOverpayOption) { if (option == DoctorOverpayOption.TrashIt) { return getString(R.string.doctor_overpay_option_one); @@ -1178,8 +1200,10 @@ private static void initActionStrings() { getCardName(Cards.artificer), getCardName(Cards.bonfire), getCardName(Cards.dungeon), + getCardName(Cards.ratcatcher), getCardName(Cards.raze), getCardName(Cards.storyteller), + getCardName(Cards.transmogrify), /*Adventures Events*/ getCardName(Cards.alms), getCardName(Cards.seaway) diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index d20224af1..b210306d6 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -43,6 +43,8 @@ public enum Type { CardSetAsideGear, // A card was set aside (gear) CardSetAsideHaven, // A card was set aside (haven) CardSetAsideOnTavernMat, // A card was set aside on tavern mat + CallingCard, // A card is about to be called from the tavern mat + CalledCard, // A card was called from the tavern mat CardSetAsideOnIslandMat, // A card was set aside on island mat DeckPutIntoDiscardPile, // Deck put into discard pile TurnJourneyTokenFaceUp, // journey token turned face up diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index f7ce60e61..f357c4741 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -14,7 +14,7 @@ /** * Gives information about cards that are selected by the player from the table (piles, hand, play) * - * This clas gives information about the constrains set on the selection of cards, e.g. what type, cost, from which place + * This class gives information about the constrains set on the selection of cards, e.g. what type, cost, from which place * */ public class SelectCardOptions implements Serializable { @@ -79,6 +79,7 @@ public enum PickType { public boolean isAttack = false; public boolean isNonShelter = false; public boolean isSupplyCard = false; + public int noTokensForPlayer = -1; public boolean passable = false; public String header = null; public ArrayList allowedCards = new ArrayList(); @@ -119,6 +120,7 @@ public enum PickType { public SelectCardOptions isNonVictory() {isNonVictory = true; return this;} public SelectCardOptions isAttack() {isAttack = true; return this;} public SelectCardOptions isSupplyCard() {isSupplyCard = true; return this;} + public SelectCardOptions noTokensForPlayer(int p) {noTokensForPlayer = p; return this;} public SelectCardOptions allowedCards(int[] is) { for (int i : is) @@ -146,13 +148,14 @@ public void addValidCard(int card) { } public boolean checkValid(MyCard c) { - return checkValid(c, 0); + return checkValid(c, 0, false); } - public boolean checkValid(MyCard c, int cost) { + public boolean checkValid(MyCard c, int cost, boolean hasTokens) { if ((maxCost >= 0) && (cost > maxCost )) return false; if ((minCost >= 0) && (cost < minCost)) return false; + if (noTokensForPlayer != -1 && hasTokens) return false; if (isAction && !c.isAction) return false; if (isReaction && !c.isReaction) return false; @@ -174,13 +177,14 @@ public boolean checkValid(MyCard c, int cost) { } public boolean checkValid(Card c, boolean cardIsVictory) { - return checkValid(c, 0, cardIsVictory); + return checkValid(c, 0, cardIsVictory, false); } - public boolean checkValid(Card c, int cost, boolean cardIsVictory) { + public boolean checkValid(Card c, int cost, boolean cardIsVictory, boolean hasTokens) { if ((maxCost >= 0) && (cost > (c.costPotion() ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; + if (noTokensForPlayer != -1 && hasTokens) return false; if (isReaction && !(Cards.isReaction(c))) return false; if (isTreasure && !(c instanceof TreasureCard)) return false; @@ -194,7 +198,7 @@ public boolean checkValid(Card c, int cost, boolean cardIsVictory) { if (isNonRats && c.equals(Cards.rats)) return false; if (c.equals(Cards.grandMarket) && copperCountInPlay > 0) return false; if (isNonShelter && c.isShelter()) return false; - + if (c instanceof ActionCard) { if (isAttack && !(((ActionCard) c).isAttack())) return false; } else { diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 9e6cc1fa3..60e39de7a 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -772,6 +772,12 @@ protected void additionalCardActions(Game game, MoveContext context, Player curr disciple(game, context, currentPlayer); break; case DistantLands: + case Duplicate: + case Guide: + case Ratcatcher: + case RoyalCarriage: + case Teacher: + case Transmogrify: case WineMerchant: putOnTavern(game, context, currentPlayer); break; diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 5899c30b0..99724332c 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -23,6 +23,7 @@ public abstract class BasePlayer extends Player implements GameEventListener { //trash in this order! protected static final Card[] EARLY_TRASH_CARDS = new Card[] { Cards.curse, Cards.rats, Cards.overgrownEstate, Cards.ruinedVillage, Cards.ruinedMarket, Cards.hovel, Cards.survivors, Cards.ruinedLibrary, Cards.abandonedMine, Cards.virtualRuins, Cards.estate }; protected static final Card[] LATE_TRASH_CARDS = new Card[] { Cards.curse, Cards.rats, Cards.overgrownEstate, Cards.ruinedVillage, Cards.ruinedMarket, Cards.survivors, Cards.ruinedLibrary, Cards.abandonedMine, Cards.virtualRuins, Cards.estate, Cards.copper, Cards.masterpiece }; + protected static final Card[] EASY_WHEN_TRASH_CARDS = new Card[] { Cards.cultist, Cards.rats, Cards.catacombs, Cards.fortress, Cards.huntingGrounds, Cards.sirVander, Cards.overgrownEstate}; protected Random rand = new Random(System.currentTimeMillis()); protected static final int COST_MAX = 11; @@ -271,6 +272,21 @@ else if (randList.contains(Cards.virtualRuins)) return null; } + + protected Card highestCard(MoveContext context, Iterable cards) { + float highestCost = -1; + Card highestCard = null; + for (Card c : cards) { + float cost = c.getCost(context); + float potionOffset = c.costPotion() ? 2.5f : 0.0f; + if (cost + potionOffset > highestCost) { + highestCost = cost + potionOffset; + highestCard = c; + } + } + return highestCard; + } + public Card lowestCard(MoveContext context, CardList cards, boolean discard) { Card[] ret = lowestCards(context, cards, 1, discard); if(ret == null) { @@ -408,6 +424,20 @@ public Card[] pickOutCards(CardList cards, int num, Card[] cardsToMatch) { return ret.toArray(new Card[0]); } + + protected ArrayList getAttackCardsLeft() { + ArrayList options = new ArrayList(); + for (AbstractCardPile pile : game.piles.values()) { + if ((pile.card() instanceof ActionCard) && (pile.getCount() > 0)) { + ActionCard ac = (ActionCard) pile.card(); + if (ac.isAttack()) { + options.add(pile.card()); + } + } + } + return options; + } + public Card[] getTrashCards() { if(turnCount < midGame) { return EARLY_TRASH_CARDS; @@ -417,6 +447,10 @@ public Card[] getTrashCards() { } } + public Card[] getEasyWhenTrashCards() { + return EASY_WHEN_TRASH_CARDS; + } + protected Card[] getReactionCards(boolean defended) { ArrayList reactionCards = new ArrayList(); boolean moatSelected = false; @@ -2281,15 +2315,7 @@ public Card armory_cardToObtain(MoveContext context) { @Override public Card squire_cardToObtain(MoveContext context) { - ArrayList options = new ArrayList(); - for (AbstractCardPile pile : game.piles.values()) { - if ((pile.card() instanceof ActionCard) && (pile.getCount() > 0)) { - ActionCard ac = (ActionCard) pile.card(); - if (ac.isAttack()) { - options.add(pile.card()); - } - } - } + ArrayList options = getAttackCardsLeft(); if (options.size() > 0) { return Util.randomCard(options); @@ -3186,6 +3212,18 @@ public Card[] artificer_cardsToDiscard(MoveContext context) { public Card artificer_cardToObtain(MoveContext context, int cost) { return bestCardInPlay(context, cost, true, false, false); } + + public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards) { + // only possible cards to call here are Duplicate or Estate (behaving like a Duplicate) + //don't duplicate trash (TODO: estate might not be trash with Inheritance) + for (Card c : getTrashCards()) { + if (c.equals(gainedCard)) + return null; + } + if (possibleCards.length > 0) + return possibleCards[0]; + return null; + } @Override public Card[] gear_cardsToSetAside(MoveContext context) { @@ -3227,6 +3265,15 @@ public boolean miser_shouldTakeTreasure(MoveContext context) { return false; } + @Override + public Card ratcatcher_cardToTrash(MoveContext context) { + Card toTrash = pickOutCard(context.getPlayer().getHand(), getTrashCards()); + if (toTrash == null) { + toTrash = lowestCard(context, getHand(), false); + } + return toTrash; + } + @Override public boolean raze_shouldTrashRazePlayed(MoveContext context) { if (getHand().size() == 0) { @@ -3282,6 +3329,92 @@ public Card raze_cardToKeep(MoveContext context, Card[] cards) { return cardToKeep; } + + @Override + public PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context) { + //get a token that hasn't been used yet if possible + ArrayList validTokens = new ArrayList(); + ArrayList unavailableTokens = new ArrayList(); + validTokens.add(PlayerSupplyToken.PlusOneCard); + validTokens.add(PlayerSupplyToken.PlusOneAction); + validTokens.add(PlayerSupplyToken.PlusOneCoin); + validTokens.add(PlayerSupplyToken.PlusOneBuy); + + for (PlayerSupplyToken token : validTokens) { + for (Card c : context.game.getCardsInGame()) { + if (context.game.isPlayerSupplyTokenOnPile(c, context.getPlayer(), token)) + unavailableTokens.add(token); + } + } + + for (PlayerSupplyToken token : unavailableTokens) + validTokens.remove(token); + + if (validTokens.size() > 0) + return validTokens.get(0); + return PlayerSupplyToken.PlusOneCard; + } + + @Override + public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token) { + // TODO: better logic based on token type and how many cards we have or want to have of the augmented card + Card[] cards = context.game.getCardsInGame(); + Arrays.sort(cards, new Util.CardCostComparatorDesc()); + for (Card c : cards) { + if (c instanceof ActionCard && + Cards.isSupplyCard(c) && + game.getPlayerSupplyTokens(c, this).size() == 0) + return (ActionCard) c; + } + return null; + } + + @Override + public Card transmogrify_cardToTrash(MoveContext context) { + CardList hand = context.getPlayer().getHand(); + + //when-trash trash cards that benefit us + Card bestCard = pickOutCard(hand, getEasyWhenTrashCards()); + if (bestCard != null) + return bestCard; + + if (getAttackCardsLeft().size() > 0 && hand.contains(Cards.squire)) { + return Cards.squire; + } + + //find best card on the table costing 1 more than the cards we have in hand - trash card from hand + bestCard = null; + int bestUpgradedCost = -1; + for (Card c : hand) { + int newCost = c.getCost(context) + 1; + Card supplyCard = bestCardInPlay(context, newCost, true, c.costPotion(), false, true, false); + if (supplyCard != null && newCost > bestUpgradedCost) { + bestCard = c; + bestUpgradedCost = newCost; + } + } + if (bestCard != null) { + return bestCard; + } + + //if not any, trash a curse, ruins or copper + if (hand.contains(Cards.curse)) return Cards.curse; + + if (!context.game.isCardInGame(Cards.poorHouse)) { + for (Card c : hand) { + if (c.isRuins()) + return c; + } + if (hand.contains(Cards.copper)) return Cards.copper; + } + + return Util.randomCard(context.getPlayer().getHand()); + } + + @Override + public Card transmogrify_cardToObtain(MoveContext context, int maxCost, boolean potion) { + return bestCardInPlay(context, maxCost, false, potion, true); + } @Override public boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) @@ -3332,7 +3465,10 @@ public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { CardList cl = new CardList(context.getPlayer(), context.getPlayer().getPlayerName()); for(Card c : cards) cl.add(c); - return lowestCard(context, cl, true); + Card toDiscard = pickOutCard(cl, getTrashCards()); + if (toDiscard == null) + toDiscard = lowestCard(context, cl, true); + return toDiscard; } @Override diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java new file mode 100644 index 000000000..ae99d08a0 --- /dev/null +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -0,0 +1,263 @@ +package com.vdom.core; + +import com.vdom.api.ActionCard; +import com.vdom.api.Card; +import com.vdom.api.GameEvent; + +public class CallableActionCardImpl extends ActionCardImpl implements CallableCard { + + private static final long serialVersionUID = 1L; + protected boolean callableWhenCardGained; + protected boolean callableWhenActionResolved; + protected boolean callableWhenTurnStarts; + protected int callableWhenCardGainedMaxCost = -1; + + protected CallableActionCardImpl(Builder builder) { + super(builder); + callableWhenCardGained = builder.callableWhenCardGained; + callableWhenActionResolved = builder.callableWhenActionResolved; + callableWhenTurnStarts = builder.callableWhenTurnStarts; + callableWhenCardGainedMaxCost = builder.callableWhenCardGainedMaxCost; + } + + public boolean isCallableWhenCardGained() { + return callableWhenCardGained; + } + + public int getCallableWhenGainedMaxCost() { + return callableWhenCardGainedMaxCost; + } + + public boolean isCallableWhenActionResolved() { + return callableWhenActionResolved; + } + + public boolean isCallableWhenTurnStarts() { + return callableWhenTurnStarts; + } + + public static class Builder extends ActionCardImpl.Builder { + protected boolean callableWhenCardGained; + protected boolean callableWhenActionResolved; + protected boolean callableWhenTurnStarts; + protected int callableWhenCardGainedMaxCost; + + public Builder(Cards.Type type, int cost) { + super(type, cost); + } + + public Builder callWhenTurnStarts() { + callableWhenTurnStarts = true; + return this; + } + + public Builder callWhenActionResolved() { + callableWhenActionResolved = true; + return this; + } + + public Builder callWhenGainCard(int maxCost) { + callableWhenCardGained = true; + callableWhenCardGainedMaxCost = maxCost; + return this; + } + + public CallableActionCardImpl build() { + return new CallableActionCardImpl(this); + } + } + + @Override + public CardImpl instantiate() { + checkInstantiateOK(); + CallableActionCardImpl c = new CallableActionCardImpl(); + copyValues(c); + return c; + } + + protected void copyValues(CallableActionCardImpl c) { + super.copyValues(c); + c.callableWhenCardGained = callableWhenCardGained; + c.callableWhenActionResolved = callableWhenActionResolved; + c.callableWhenTurnStarts = callableWhenTurnStarts; + c.callableWhenCardGainedMaxCost = callableWhenCardGainedMaxCost; + } + + protected CallableActionCardImpl() { + } + + private boolean call(MoveContext context) { + Player currentPlayer = context.getPlayer(); + if (!currentPlayer.tavern.remove(this.controlCard)) { + return false; + } + currentPlayer.playedCards.add(this.controlCard); + GameEvent event = new GameEvent(GameEvent.Type.CallingCard, (MoveContext) context); + event.card = this.controlCard; + context.game.broadcastEvent(event); + return true; + } + + private void finishCall(MoveContext context) { + GameEvent event = new GameEvent(GameEvent.Type.CalledCard, (MoveContext) context); + event.card = this.controlCard; + context.game.broadcastEvent(event); + } + + public void callWhenCardGained(MoveContext context, Card cardToGain) { + if (!callableWhenCardGained) return; + if (!call(context)) return; + Game game = context.game; + Player currentPlayer = context.getPlayer(); + switch (this.getType()) { + case Duplicate: + duplicate(cardToGain, context, game, currentPlayer); + break; + default: + break; + } + finishCall(context); + } + + public void callWhenActionResolved(MoveContext context, Card resolvedAction) { + if (!callableWhenActionResolved) return; + if (!call(context)) return; + Game game = context.game; + Player currentPlayer = context.getPlayer(); + switch (this.getType()) { + case RoyalCarriage: + royalCarriage(resolvedAction, context, game, currentPlayer); + default: + break; + } + finishCall(context); + } + + public void callAtStartOfTurn(MoveContext context) { + if (!callableWhenTurnStarts) return; + if (!call(context)) return; + Game game = context.game; + Player currentPlayer = context.getPlayer(); + switch (this.getType()) { + case Guide: + guide(context, game, currentPlayer); + break; + case Ratcatcher: + ratcatcher(context, game, currentPlayer); + break; + case Teacher: + teacher(context, game, currentPlayer); + break; + case Transmogrify: + transmogrify(context, game, currentPlayer); + break; + default: + break; + } + finishCall(context); + } + + private void duplicate(Card cardToGain, MoveContext context, Game game, Player currentPlayer) { + currentPlayer.gainNewCard(cardToGain, this.controlCard, context); + } + + private void guide(MoveContext context, Game game, Player currentPlayer) { + if (currentPlayer.getHand().size() > 0) { + while (!currentPlayer.getHand().isEmpty()) { + currentPlayer.discard(currentPlayer.getHand().remove(0), this.controlCard, context); + } + } + for (int i = 0; i < 5; ++i) { + game.drawToHand(currentPlayer, this.controlCard); + } + + } + + private void ratcatcher(MoveContext context, Game game, Player currentPlayer) { + if (currentPlayer.getHand().size() == 0) { + return; + } + Card cardToTrash = currentPlayer.controlPlayer.ratcatcher_cardToTrash((MoveContext) context); + if (cardToTrash != null) { + if (!currentPlayer.getHand().contains(cardToTrash)) { + Util.playerError(currentPlayer, "Ratcatcher error, invalid card to trash, trashing random card."); + cardToTrash = Util.randomCard(currentPlayer.getHand()); + } else { + currentPlayer.hand.remove(cardToTrash); + currentPlayer.trash(cardToTrash, null, context); + } + } + } + + private void royalCarriage(Card resolvedAction, MoveContext context, Game game, Player currentPlayer) { + // TODO Auto-generated method stub + + } + + private void teacher(MoveContext context, Game game, Player currentPlayer) { + //look to see if we have a free pile + int numFreePiles = 0; + ActionCard lastFreePile = null; + for (Card c : game.getCardsInGame()) { + if (game.getPile(c).isSupply() + && c instanceof ActionCard + && game.getPlayerSupplyTokens(c, currentPlayer).size() == 0) { + numFreePiles++; + lastFreePile = (ActionCard) c; + break; + } + } + if (numFreePiles == 0) + return; + + PlayerSupplyToken token = currentPlayer.controlPlayer.teacher_tokenTypeToMove(context); + + if (token == null || !(token == PlayerSupplyToken.PlusOneCard || + token == PlayerSupplyToken.PlusOneAction || + token == PlayerSupplyToken.PlusOneBuy || + token == PlayerSupplyToken.PlusOneCoin)) { + Util.playerError(currentPlayer, "Teacher error: didn't select a valid token to move, selecting +Buy"); + token = PlayerSupplyToken.PlusOneBuy; + } + + ActionCard card; + if (numFreePiles == 1) { + card = lastFreePile; + } else { + card = context.getPlayer().controlPlayer.teacher_actionCardPileToHaveToken(context, token); + } + + placeToken(context, card, token); + } + + private void transmogrify(MoveContext context, Game game, Player currentPlayer) { + if (currentPlayer.getHand().size() == 0) { + return; + } + Card cardToTrash = currentPlayer.controlPlayer.transmogrify_cardToTrash(context); + if (cardToTrash != null) { + if (!currentPlayer.getHand().contains(cardToTrash)) { + Util.playerError(currentPlayer, "Transmogrify error, invalid card to trash, trashing random card."); + cardToTrash = Util.randomCard(currentPlayer.getHand()); + } else { + currentPlayer.hand.remove(cardToTrash); + currentPlayer.trash(cardToTrash, null, context); + } + } + int value = cardToTrash.getCost(context) + 1; + boolean potion = cardToTrash.costPotion(); + + Card card = currentPlayer.controlPlayer.transmogrify_cardToObtain(context, value, potion); + if (card != null) { + if (card.getCost(context) > value || (card.costPotion() && !potion)) { + Util.playerError(currentPlayer, "Transmogrify error, new card does not cost value of the old card +1."); + } else if (game.isPileEmpty(card)) { + Util.playerError(currentPlayer, "Transmogrify error, new card pile is empty."); + } else if (!game.isCardInGame(card)) { + Util.playerError(currentPlayer, "Transmogrify error, new card not in game."); + } else { + currentPlayer.gainNewCard(card, this.controlCard, context); + } + } + } +} diff --git a/vdom/src/com/vdom/core/CallableCard.java b/vdom/src/com/vdom/core/CallableCard.java new file mode 100644 index 000000000..c62f4687b --- /dev/null +++ b/vdom/src/com/vdom/core/CallableCard.java @@ -0,0 +1,19 @@ +package com.vdom.core; + +import com.vdom.api.Card; + +public interface CallableCard extends Card { + public boolean isCallableWhenCardGained(); + + public int getCallableWhenGainedMaxCost(); + + public boolean isCallableWhenActionResolved(); + + public boolean isCallableWhenTurnStarts(); + + public void callWhenCardGained(MoveContext context, Card cardToGain); + + public void callWhenActionResolved(MoveContext context, Card resolvedAction); + + public void callAtStartOfTurn(MoveContext context); +} diff --git a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java new file mode 100644 index 000000000..bf4aae61a --- /dev/null +++ b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java @@ -0,0 +1,146 @@ +package com.vdom.core; + +import com.vdom.api.Card; +import com.vdom.api.GameEvent; + +public class CallableTreasureCardImpl extends TreasureCardImpl implements CallableCard { + + private static final long serialVersionUID = 1L; + protected boolean callableWhenCardGained; + protected boolean callableWhenActionResolved; + protected boolean callableWhenTurnStarts; + protected int callableWhenCardGainedMaxCost = -1; + + protected CallableTreasureCardImpl(Builder builder) { + super(builder); + callableWhenCardGained = builder.callableWhenCardGained; + callableWhenActionResolved = builder.callableWhenActionResolved; + callableWhenTurnStarts = builder.callableWhenTurnStarts; + callableWhenCardGainedMaxCost = builder.callableWhenCardGainedMaxCost; + } + + public boolean isCallableWhenCardGained() { + return callableWhenCardGained; + } + + public int getCallableWhenGainedMaxCost() { + return callableWhenCardGainedMaxCost; + } + + public boolean isCallableWhenActionResolved() { + return callableWhenActionResolved; + } + + public boolean isCallableWhenTurnStarts() { + return callableWhenTurnStarts; + } + + public static class Builder extends TreasureCardImpl.Builder { + + protected boolean callableWhenCardGained; + protected boolean callableWhenActionResolved; + protected boolean callableWhenTurnStarts; + protected int callableWhenCardGainedMaxCost; + + public Builder(Cards.Type type, int cost, int value) { + super(type, cost, value); + } + + public Builder callWhenTurnStarts() { + callableWhenTurnStarts = true; + return this; + } + + public Builder callWhenActionResolved() { + callableWhenActionResolved = true; + return this; + } + + public Builder callWhenGainCard(int maxCost) { + callableWhenCardGained = true; + callableWhenCardGainedMaxCost = maxCost; + return this; + } + + public CallableTreasureCardImpl build() { + return new CallableTreasureCardImpl(this); + } + } + + @Override + public CardImpl instantiate() { + checkInstantiateOK(); + CallableTreasureCardImpl c = new CallableTreasureCardImpl(); + copyValues(c); + return c; + } + + protected void copyValues(CallableTreasureCardImpl c) { + super.copyValues(c); + c.callableWhenCardGained = callableWhenCardGained; + c.callableWhenActionResolved = callableWhenActionResolved; + c.callableWhenTurnStarts = callableWhenTurnStarts; + c.callableWhenCardGainedMaxCost = callableWhenCardGainedMaxCost; + } + + protected CallableTreasureCardImpl() { + } + + private boolean call(MoveContext context) { + Player currentPlayer = context.getPlayer(); + if (!currentPlayer.tavern.remove(this.controlCard)) { + return false; + } + currentPlayer.playedCards.add(this.controlCard); + GameEvent event = new GameEvent(GameEvent.Type.CallingCard, (MoveContext) context); + event.card = this.controlCard; + context.game.broadcastEvent(event); + return true; + } + + private void finishCall(MoveContext context) { + GameEvent event = new GameEvent(GameEvent.Type.CalledCard, (MoveContext) context); + event.card = this.controlCard; + context.game.broadcastEvent(event); + } + + public void callWhenCardGained(MoveContext context, Card cardToGain) { + if (!callableWhenCardGained) return; + if (!call(context)) return; + switch (this.getType()) { + default: + break; + } + finishCall(context); + } + + public void callWhenActionResolved(MoveContext context, Card resolvedAction) { + if (!callableWhenActionResolved) return; + if (!call(context)) return; + Game game = context.game; + Player currentPlayer = context.getPlayer(); + switch (this.getType()) { + case CoinOfTheRealm: + coinOfTheRealm(context, game, currentPlayer); + break; + default: + break; + } + finishCall(context); + } + + public void callAtStartOfTurn(MoveContext context) { + if (!callableWhenTurnStarts) return; + if (!call(context)) return; + switch (this.getType()) { + default: + break; + } + finishCall(context); + } + + private void coinOfTheRealm(MoveContext context, Game game, + Player currentPlayer) { + context.actions += 2; + } +} diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index b6a7a68b1..20b2b1568 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -1,5 +1,6 @@ package com.vdom.core; +import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.VictoryCard; @@ -383,6 +384,22 @@ public CardImpl getControlCard() { void setControlCard(CardImpl controlCard) { this.controlCard = controlCard; } + + protected void placeToken(MoveContext context, ActionCard card, PlayerSupplyToken token) { + if (card == null) { + Card[] cards = context.game.getActionsInGame(); + if (cards.length != 0) { + Util.playerError(context.getPlayer(), getName() + " error: did not pick a valid pile, ignoring."); + } + return; + } + if (!context.game.cardInGame(card) || + !Cards.isSupplyCard(card)) { + Util.playerError(context.getPlayer(), getName() + " error: Invalid pile chosen, ignoring"); + } + + context.game.movePlayerSupplyToken(card, context.getPlayer(), token); + } /*@Override public void isGained(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index d58ec3023..02341ee98 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -703,13 +703,13 @@ public enum Type { actionCardsAdventures.add(artificer = new ActionCardImpl.Builder(Cards.Type.Artificer, 5).addCards(1).addActions(1).addGold(1).description("Discard any number of cards. You may gain a card costing exactly 1 Coin per card discarded, putting it on top of your deck.").expansion("Adventures").build()); actionCardsAdventures.add(bridgeTroll = new ActionDurationCardImpl.Builder(Cards.Type.BridgeTroll, 5).addBuysNextTurn(1).addBuys(1).attack().description("Each other player takes his -1 Coin token. ~ While this is in play, cards cost 1 Coin less on your turns, but not less than 0 Coins.").expansion("Adventures").build()); actionCardsAdventures.add(caravanGuard = new ActionDurationCardImpl.Builder(Cards.Type.CaravanGuard, 3).addGoldNextTurn(1).addCards(1).addActions(1).description("When another player plays an Attack card, you may play this from your hand. (+1 Action has no effect if it's not your turn.)").expansion("Adventures").build()); - actionCardsAdventures.add(coinOfTheRealm = new TreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); + actionCardsAdventures.add(coinOfTheRealm = new CallableTreasureCardImpl.Builder(Cards.Type.CoinOfTheRealm, 2, 1).callWhenActionResolved().isReserve().description("When you play this, put it on your Tavern mat. ~ Directly after resolving an Action, you may call this, for +2 Actions.").expansion("Adventures").build()); actionCardsAdventures.add(distantLands = new ActionVictoryCardImpl.Builder(Cards.Type.DistantLands, 5).isReserve().description("Put this on your Tavern mat. ~ Worth 4 VP if on your Tavern mat at the end of the game (otherwise worth 0 VP).").expansion("Adventures").build()); actionCardsAdventures.add(dungeon = new ActionDurationCardImpl.Builder(Cards.Type.Dungeon, 3).addCards(2).addActions(1).description("Discard 2 cards. At the start of your next turn: +2 Cards, then discard 2 cards.").expansion("Adventures").build()); - actionCardsAdventures.add(duplicate = new ActionCardImpl.Builder(Cards.Type.Duplicate, 3).isReserve().description("Put this on your Tavern mat. ~ When you gain a card costing up to 6 Coins, you may call this, to gain a copy of that card.").expansion("Adventures").build()); + actionCardsAdventures.add(duplicate = new CallableActionCardImpl.Builder(Cards.Type.Duplicate, 4).callWhenGainCard(6).isReserve().description("Put this on your Tavern mat. ~ When you gain a card costing up to 6 Coins, you may call this, to gain a copy of that card.").expansion("Adventures").build()); actionCardsAdventures.add(gear = new ActionDurationCardImpl.Builder(Cards.Type.Gear, 3).addCards(2).description("Set aside up to 2 cards from your hand face down. At the start of your next turn, put them into your hand.").expansion("Adventures").build()); actionCardsAdventures.add(giant = new ActionCardImpl.Builder(Cards.Type.Giant, 5).attack().description("Turn your Journey token over (it starts face up). If it's face down, +1 Coin. If it's face up, +5 Coins, and each other player reveals the top card of his deck, trashes it if it costs from 3 to 6 Coins, and otherwise discards it and gains a Curse.").expansion("Adventures").build()); - actionCardsAdventures.add(guide = new ActionCardImpl.Builder(Cards.Type.Guide, 3).addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to discard your hand and draw 5 cards.").expansion("Adventures").build()); + actionCardsAdventures.add(guide = new CallableActionCardImpl.Builder(Cards.Type.Guide, 3).callWhenTurnStarts().addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to discard your hand and draw 5 cards.").expansion("Adventures").build()); actionCardsAdventures.add(hauntedWoods = new ActionDurationCardImpl.Builder(Cards.Type.HauntedWoods, 5).addCardsNextTurn(3).attack().description("Until your next turn, when any other player buys a card, he puts his hand on top of his deck in any order.").expansion("Adventures").build()); actionCardsAdventures.add(hireling = new ActionDurationCardImpl.Builder(Cards.Type.Hireling, 6).description("At the start of each of your turns for the rest of the game: +1 Card. (This stays in play.)").expansion("Adventures").build()); actionCardsAdventures.add(lostCity = new ActionCardImpl.Builder(Cards.Type.LostCity, 5).addCards(2).addActions(2).description("When you gain this, each other player draws a card.").expansion("Adventures").build()); @@ -720,13 +720,13 @@ public enum Type { actionCardsAdventures.add(peasant = new ActionCardImpl.Builder(Cards.Type.Peasant, 2).addGold(1).addBuys(1).isTraveller().description("When you discard this from play, you may exchange it for a Soldier.").expansion("Adventures").build()); actionCardsAdventures.add(port = new ActionCardImpl.Builder(Cards.Type.Port, 4).addCards(1).addActions(2).description("When you buy this, gain another Port.").expansion("Adventures").build()); actionCardsAdventures.add(ranger = new ActionCardImpl.Builder(Cards.Type.Ranger, 4).addBuys(1).description("Turn your Journey token over (it starts face up). If it's face up, +5 Cards.").expansion("Adventures").build()); - actionCardsAdventures.add(ratcatcher = new ActionCardImpl.Builder(Cards.Type.Ratcatcher, 2).addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand.").expansion("Adventures").build()); + actionCardsAdventures.add(ratcatcher = new CallableActionCardImpl.Builder(Cards.Type.Ratcatcher, 2).callWhenTurnStarts().addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand.").expansion("Adventures").build()); actionCardsAdventures.add(raze = new ActionCardImpl.Builder(Cards.Type.Raze, 2).addActions(1).description("Trash this or a card from your hand. Look at a number of cards from the top of your deck equal to the cost in Coins of the trashed card. Put one into your hand and discard the rest.").expansion("Adventures").build()); actionCardsAdventures.add(relic = new TreasureCardImpl.Builder(Cards.Type.Relic, 5, 2).attack().description("When you play this, each other player puts his -1 Card token on his deck.").expansion("Adventures").build()); - actionCardsAdventures.add(royalCarriage = new ActionCardImpl.Builder(Cards.Type.RoyalCarriage, 5).addActions(1).isReserve().description("Put this on your Tavern mat. ~ Directly after resolving an Action, if it's still in play, you may call this, to replay that Action.").expansion("Adventures").build()); + actionCardsAdventures.add(royalCarriage = new CallableActionCardImpl.Builder(Cards.Type.RoyalCarriage, 5).callWhenActionResolved().addActions(1).isReserve().description("Put this on your Tavern mat. ~ Directly after resolving an Action, if it's still in play, you may call this, to replay that Action.").expansion("Adventures").build()); actionCardsAdventures.add(storyteller = new ActionCardImpl.Builder(Cards.Type.Storyteller, 5).addGold(1).addActions(1).description("Play up to 3 Treasures from your hand. Pay all of your Coins; +1 Card per Coin paid.").expansion("Adventures").build()); actionCardsAdventures.add(swampHag = new ActionDurationCardImpl.Builder(Cards.Type.SwampHag, 5).addGoldNextTurn(3).attack().description("Until your next turn, when any other player buys a card, he gains a Curse.").expansion("Adventures").build()); - actionCardsAdventures.add(transmogrify = new ActionCardImpl.Builder(Cards.Type.Transmogrify, 4).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand, gain a card costing up to 1 Coin more than it, and put that card into your hand.").expansion("Adventures").build()); + actionCardsAdventures.add(transmogrify = new CallableActionCardImpl.Builder(Cards.Type.Transmogrify, 4).callWhenTurnStarts().addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand, gain a card costing up to 1 Coin more than it, and put that card into your hand.").expansion("Adventures").build()); actionCardsAdventures.add(treasureTrove = new TreasureCardImpl.Builder(Cards.Type.TreasureTrove, 5, 2).description("When you play this, gain a Gold and a Copper.").expansion("Adventures").build()); actionCardsAdventures.add(wineMerchant = new ActionCardImpl.Builder(Cards.Type.WineMerchant, 5).addGold(4).addBuys(1).isReserve().description("Put this on your Tavern mat. ~ At the end of your Buy phase, if you have at least 2 Coins unspent, you may discard this from your Tavern mat.").expansion("Adventures").build()); @@ -759,7 +759,7 @@ public enum Type { nonSupplyCards.add(fugitive = new ActionCardImpl.Builder(Cards.Type.Fugitive , 4).addCards(2).addActions(1).isTraveller().description("Discard a card. ~ When you discard this from play, you may exchange it for a Disciple.").expansion("Adventures").build()); nonSupplyCards.add(hero = new ActionCardImpl.Builder(Cards.Type.Hero , 5).addGold(2).isTraveller().description("Gain a Treasure - When you discard this from play, you may exchange it for a Champion.").expansion("Adventures").build()); nonSupplyCards.add(soldier = new ActionCardImpl.Builder(Cards.Type.Soldier , 3).addGold(2).isTraveller().attack().description("+1 Coin per other Attack you have in play. Each other player with 4 or more cards in hand discards a card. ~ When you discard this from play, you may exchange it for a Fugitive.").expansion("Adventures").build()); - nonSupplyCards.add(teacher = new ActionCardImpl.Builder(Cards.Type.Teacher , 6).description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 Coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus).").expansion("Adventures").build()); + nonSupplyCards.add(teacher = new CallableActionCardImpl.Builder(Cards.Type.Teacher , 6).callWhenTurnStarts().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 Coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus).").expansion("Adventures").build()); nonSupplyCards.add(treasureHunter = new ActionCardImpl.Builder(Cards.Type.TreasureHunter , 3).addGold(1).addActions(1).isTraveller().description("Gain a Silver per card the player to your right gained in his last turn. ~ When you discard this from play, you may exchange it for a Warrior.").expansion("Adventures").build()); nonSupplyCards.add(warrior = new ActionCardImpl.Builder(Cards.Type.Warrior , 4).addCards(2).isTraveller().attack().description("For each Traveller you have in play (including this), each other player discards the top card of his deck and trashes it if it costs 3 or 4 Coins. ~ When you discard this from play, you may exchange it for a Hero.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 0f39f9968..9371a1e40 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -99,22 +99,6 @@ public void isBuying(MoveContext context) { } } - private void placeToken(MoveContext context, ActionCard card, PlayerSupplyToken token) { - if (card == null) { - Card[] cards = context.game.getActionsInGame(); - if (cards.length != 0) { - Util.playerError(context.getPlayer(), getName() + " error: did not pick a valid pile, ignoring."); - } - return; - } - if (!context.game.cardInGame(card) || - !Cards.isSupplyCard(card)) { - Util.playerError(context.getPlayer(), getName() + " error: Invalid pile chosen, ignoring"); - } - - context.game.movePlayerSupplyToken(card, context.getPlayer(), token); - } - public void alms(MoveContext context) { boolean noTreasureCard = true; for(Card card : context.player.playedCards) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 9041c0c82..ed9d5a25d 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -280,6 +280,14 @@ void start() throws ExitException { // Discard, draw new hand // ///////////////////////////////// player.cleanup(context); + + //clean up other players cards in play without future duration effects, e.g. Duplicate + for (Player otherPlayer : getPlayersInTurnOrder()) { + if (otherPlayer != player) { + otherPlayer.cleanupOutOfTurn(new MoveContext(this, otherPlayer)); + } + } + boolean takeAnotherTurn = playerEndTurn(player, context); gameOver = checkGameOver(); @@ -1668,6 +1676,7 @@ protected void initPlayers(int numPlayers, boolean isRandom) throws ExitExceptio String[] playerStartupInfo = playerClassesAndJars.get(i); if (playerStartupInfo[1] == null) { players[i] = (Player) Class.forName(playerStartupInfo[0]).newInstance(); + players[i].setPlayerIndex(i); } else { String key = playerStartupInfo[0] + "::" + playerStartupInfo[1]; // players[i] = cachedPlayers.get(key); @@ -1687,6 +1696,7 @@ protected void initPlayers(int numPlayers, boolean isRandom) throws ExitExceptio } players[i] = (Player) playerClass.newInstance(); + players[i].setPlayerIndex(i); } if(playerStartupInfo[2] != null) { players[i].setName(playerStartupInfo[2]); @@ -2281,8 +2291,9 @@ public void gameEvent(GameEvent event) { return; } - if (event.getType() == GameEvent.Type.CardObtained || event.getType() == GameEvent.Type.BuyingCard) { - + if ((event.getType() == GameEvent.Type.CardObtained || event.getType() == GameEvent.Type.BuyingCard) && + !event.card.isEvent()) { + MoveContext context = event.getContext(); Player player = context.getPlayer(); @@ -2400,7 +2411,7 @@ public void gameEvent(GameEvent event) { } else if (event.card.equals(Cards.silver)) { player.discard.add(event.card); } - } else if (r.equals(Cards.tradingPost) || r.equals(Cards.mine) || r.equals(Cards.explorer) || r.equals(Cards.torturer)) { + } else if (r.equals(Cards.tradingPost) || r.equals(Cards.mine) || r.equals(Cards.explorer) || r.equals(Cards.torturer) || r.equals(Cards.transmogrify)) { player.hand.add(event.card); } else if (r.equals(Cards.illGottenGains) && event.card.equals(Cards.copper)) { player.hand.add(event.card); @@ -2411,6 +2422,28 @@ public void gameEvent(GameEvent event) { player.discard(event.card, null, null, commandedDiscard, false); } } + + ArrayList callableCards = new ArrayList(); + for (Card c : player.tavern) { + if (c.behaveAsCard() instanceof CallableCard) { + if (!((CallableCard)c.behaveAsCard()).isCallableWhenCardGained()) + continue; + int callCost = ((CallableCard)c.behaveAsCard()).getCallableWhenGainedMaxCost(); + if (callCost == -1 || event.card.getCost(context) <= callCost) { + callableCards.add((CallableCard) c); + } + } + } + if (!callableCards.isEmpty()) { + //ask player which card to call + Collections.sort(callableCards, new Util.CardCostComparator()); + // we want null entry at the end for None + CallableCard[] cardsAsArray = callableCards.toArray(new CallableCard[callableCards.size() + 1]); + CallableCard toCall = player.controlPlayer.call_whenGainCardToCall(context, event.card, cardsAsArray); + if (toCall != null || callableCards.contains(toCall)) { + toCall.callWhenCardGained(context, event.card); + } + } if (event.card.equals(Cards.illGottenGains)) { for(Player targetPlayer : getPlayersInTurnOrder()) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index e53ec3cc1..d938f6f7b 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -34,6 +34,15 @@ public Card nameToCard(String o, Card[] cards) { public boolean selectBoolean(MoveContext context, Card cardResponsible) { return selectBoolean(context, cardResponsible, null); } + + public static final String OPTION_REACTION = "REACTION"; + public static final String OPTION_PUTBACK = "PUTBACK"; + public static final String OPTION_SPEND_GUILD_COINS = "GUILDCOINS"; + public static final String OPTION_OVERPAY = "OVERPAY"; + public static final String OPTION_OVERPAY_POTION = "OVERPAYP"; + public static final String OPTION_CALL_WHEN_GAIN = "CALLWHENGAIN"; + public static final String OPTION_CALL_RESOLVE_ACTION = "CALLAFTERACTION"; + public static final String OPTION_START_TURN_EFFECT = "STARTTURN"; abstract protected int selectOption(MoveContext context, Card card, Object[] options); abstract protected int[] orderCards(MoveContext context, int[] cards); @@ -84,7 +93,7 @@ private Card[] getFromHandOrPlayed(boolean fromTheHand, MoveContext context, Sel ArrayList handList = new ArrayList(); for (Card card : localHand) { - if (sco.checkValid(card, card.getCost(context), card.isVictory(context))) { + if (sco.checkValid(card, card.getCost(context), card.isVictory(context), false)) { handList.add(card); sco.addValidCard(cardToInt(card)); } @@ -135,9 +144,10 @@ private Card getFromTable(MoveContext context, SelectCardOptions sco) { Card[] cards = context.getCardsInGame(); for (Card card : cards) { + boolean hasTokens = context.game.getPlayerSupplyTokens(card, context.getPlayer()).size() > 0; if ( !(card.isEvent() && sco.cardResponsible != null && sco.cardResponsible.equals(Cards.contraband) ) && (sco.allowEmpty || !context.game.isPileEmpty(card))) { - if ( sco.checkValid(card, card.getCost(context), card.isVictory(context)) + if ( sco.checkValid(card, card.getCost(context), card.isVictory(context), hasTokens) && ( !context.cantBuy.contains(card) || !sco.pickType.equals(PickType.BUY)) && !( !Cards.isSupplyCard(card) @@ -1809,12 +1819,7 @@ public Card getAttackReaction(MoveContext context, Card responsible, boolean def if (cards.size() > 0) { cards.add(null); Object[] options = new Object[1 + cards.size()]; - // TODO(matt): this is quite a bit hackish. But it should work. At the very - // least, though, this string should be hard-coded somewhere else in a constant - // somewhere, and reused in the ui.Strings methods. There are a number of places - // in the code that should be similarly fixed ("PUTBACK", "OVERPAY", "GUILDCOINS", - // and "OVERPAYP"). - options[0] = "REACTION"; + options[0] = OPTION_REACTION; for (int i = 0; i < cards.size(); i++) { options[i + 1] = cards.get(i); } @@ -1842,7 +1847,7 @@ public PutBackOption selectPutBackOption(MoveContext context, List 0) { - return selectInt(context, null, availablePotions, "OVERPAYP"); + return selectInt(context, null, availablePotions, OPTION_OVERPAY_POTION); } else { return 0; @@ -2592,6 +2597,21 @@ public Card artificer_cardToObtain(MoveContext context, int cost) { .setActionType(ActionType.GAIN).setCardResponsible(Cards.artificer); return getFromTable(context, sco); } + + @Override + public CallableCard call_whenGainCardToCall(MoveContext context, + Card gainedCard, CallableCard[] possibleCards) { + if(context.isQuickPlay() && shouldAutoPlay_call_whenGainCardToCall(context, gainedCard, possibleCards)) { + return super.call_whenGainCardToCall(context, gainedCard, possibleCards); + } + + Object[] options = new Object[1 + possibleCards.length]; + options[0] = OPTION_CALL_WHEN_GAIN; + for (int i = 0; i < possibleCards.length; i++) { + options[i + 1] = possibleCards[i]; + } + return possibleCards[selectOption(context, gainedCard, options)]; + } @Override public Card[] gear_cardsToSetAside(MoveContext context) { @@ -2632,6 +2652,16 @@ public boolean miser_shouldTakeTreasure(MoveContext context) { return selectBoolean(context, Cards.miser, extras); } + @Override + public Card ratcatcher_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_ratcatcher_cardToTrash(context)) { + return super.ratcatcher_cardToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setPickType(PickType.TRASH) + .setActionType(ActionType.TRASH).setCardResponsible(Cards.ratcatcher); + return getCardFromHand(context, sco); + } + @Override public boolean raze_shouldTrashRazePlayed(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_raze_shouldTrashRazePlayed(context)) { @@ -2657,6 +2687,52 @@ public Card raze_cardToKeep(MoveContext context, Card[] cards) { } return cards[selectOption(context, Cards.raze, cards)]; } + + @Override + public PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_teacher_tokenTypeToMove(context)) { + return super.teacher_tokenTypeToMove(context); + } + PlayerSupplyToken[] options = new PlayerSupplyToken[]{ + PlayerSupplyToken.PlusOneCard, + PlayerSupplyToken.PlusOneAction, + PlayerSupplyToken.PlusOneBuy, + PlayerSupplyToken.PlusOneCoin + }; + return options[selectOption(context, Cards.teacher, options)]; + } + + @Override + public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, + PlayerSupplyToken token) { + if(context.isQuickPlay() && shouldAutoPlay_teacher_actionCardPileToHaveToken(context, token)) { + return super.teacher_actionCardPileToHaveToken(context, token); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().noTokensForPlayer(context.getPlayer().getPlayerIndex()).setCardResponsible(Cards.teacher); + //TODO: specify can only select piles without a token + return (ActionCard) getFromTable(context, sco); + } + + @Override + public Card transmogrify_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_transmogrify_cardToTrash(context)) { + return super.transmogrify_cardToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setPickType(PickType.TRASH) + .setActionType(ActionType.TRASH).setCardResponsible(Cards.transmogrify); + return getCardFromHand(context, sco); + } + + @Override + public Card transmogrify_cardToObtain(MoveContext context, int maxCost, boolean potion) { + if(context.isQuickPlay() && shouldAutoPlay_transmogrify_cardToObtain(context, maxCost, potion)) { + return super.transmogrify_cardToObtain(context, maxCost, potion); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(maxCost).potionCost(potion?1:0) + .setCardResponsible(Cards.transmogrify).setActionType(ActionType.GAIN); + return getFromTable(context, sco); + } @Override public boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 4dd0690fc..91ca10f65 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -27,6 +27,7 @@ public abstract class Player { // Only used by InteractivePlayer currently private String name; + private int playerIndex; public int playerNumber; public int shuffleCount = 0; protected int turnCount = 0; @@ -85,6 +86,14 @@ public boolean isAi() { public void setName(String name) { this.name = name.replace("_", " "); } + + public void setPlayerIndex(int value) { + playerIndex = value; + } + + public int getPlayerIndex() { + return playerIndex; + } public int getCurrencyTotal(MoveContext context) { int coin = 0; @@ -302,6 +311,18 @@ private Card findCard(MoveContext context, Card template) { } return null; } + + protected void cleanupOutOfTurn(MoveContext context) { + //So far now, only cards that can happen here are Duplicate + // and Coin of the Realm (when called after playing a Caravan Guard as part of a Reaction) + for (Card card : playedCards) { + CardImpl actualCard = (CardImpl) card; + actualCard.cloneCount = 1; + } + while (!playedCards.isEmpty()) { + discard(playedCards.remove(0), null, context, false, true); + } + } protected void cleanup(MoveContext context) { // ///////////////////////////////// @@ -1699,14 +1720,20 @@ public ArrayList getActionsInHand() { public abstract Card amulet_cardToTrash(MoveContext context); public abstract Card[] artificer_cardsToDiscard(MoveContext context); public abstract Card artificer_cardToObtain(MoveContext context, int cost); + public abstract CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards); public abstract Card[] gear_cardsToSetAside(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); public abstract Card messenger_cardToObtain(MoveContext context); public abstract boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible); public abstract boolean miser_shouldTakeTreasure(MoveContext context); + public abstract Card ratcatcher_cardToTrash(MoveContext context); public abstract boolean raze_shouldTrashRazePlayed(MoveContext context); public abstract Card raze_cardToTrash(MoveContext context); public abstract Card raze_cardToKeep(MoveContext context, Card[] cards); + public abstract PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context); + public abstract ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token); + public abstract Card transmogrify_cardToTrash(MoveContext context); + public abstract Card transmogrify_cardToObtain(MoveContext context, int maxCost, boolean potion); public abstract int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTotal); // /////////////////////////////////////////////// diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 498831b37..85649119f 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -821,6 +821,11 @@ public boolean shouldAutoPlay_artificer_cardToObtain(MoveContext context, int co return false; } + public boolean shouldAutoPlay_call_whenGainCardToCall(MoveContext context, + Card gainedCard, CallableCard[] possibleCards) { + return false; + } + public boolean shouldAutoPlay_messenger_shouldDiscardDeck(MoveContext context, Card responsible) { return true; } @@ -833,6 +838,10 @@ public boolean shouldAutoPlay_miser_shouldTakeTreasure(MoveContext context) { return true; } + public boolean shouldAutoPlay_ratcatcher_cardToTrash(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_raze_shouldTrashRazePlayed(MoveContext context) { if (getHand().size() == 0) { return true; @@ -847,6 +856,22 @@ public boolean shouldAutoPlay_raze_cardToTrash(MoveContext context) { public boolean shouldAutoPlay_raze_cardToKeep(MoveContext context) { return false; } + + public boolean shouldAutoPlay_teacher_tokenTypeToMove(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token) { + return false; + } + + public boolean shouldAutoPlay_transmogrify_cardToTrash(MoveContext context) { + return false; + } + + public boolean shouldAutoPlay_transmogrify_cardToObtain(MoveContext context, int maxCost, boolean potion) { + return false; + } public boolean shouldAutoPlay_traveller_shouldExchange(MoveContext context, Card traveller, Card exchange) { return true; diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index a52c4409a..0159835b4 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -131,14 +131,14 @@ public boolean playTreasure(MoveContext context, boolean isClone) { } else if (equals(Cards.illGottenGains)) { reevaluateTreasures = illGottenGains(context, player, reevaluateTreasures); } else if (equals(Cards.counterfeit)) { - reevaluateTreasures = counterfeit(context, game, reevaluateTreasures, player); + reevaluateTreasures = counterfeit(context, game, reevaluateTreasures, player); } else if (equals(Cards.treasureTrove)) { - treasureTrove(context, player, game); + treasureTrove(context, player, game); } else if (equals(Cards.relic)) { - relic(context, player, game); - } - else if (equals(Cards.spoils)) - { + relic(context, player, game); + } else if (equals(Cards.coinOfTheRealm)) { + putOnTavern(game, context, player); + } else if (equals(Cards.spoils)) { if (!isClone) { // Return to the spoils pile AbstractCardPile pile = game.getPile(this); @@ -277,7 +277,7 @@ protected boolean counterfeit(MoveContext context, Game game, boolean reevaluate // A counterfeited card will not count in the calculations of future cards that care about the number of treasures played (such as Bank) context.treasuresPlayedSoFar--; - if (!treasure.equals(Cards.spoils)) { + if (!(treasure.equals(Cards.spoils) || treasure.equals(Cards.coinOfTheRealm))) { if (currentPlayer.playedCards.getLastCard().equals(treasure)) { currentPlayer.playedCards.remove(treasure); currentPlayer.trash(treasure, this, context); @@ -332,5 +332,22 @@ protected void relic(MoveContext context, Player player, Game game) { MoveContext targetContext = new MoveContext(context.game, targetPlayer); targetPlayer.setMinusOneCardToken(true, targetContext); } - } + } + + private void putOnTavern(Game game, MoveContext context, Player currentPlayer) { + // counterfeit has here no effect since card is already put on tavern + // Move to tavern mat + if (this.controlCard.numberTimesAlreadyPlayed == 0) { + currentPlayer.playedCards.remove(currentPlayer.playedCards.lastIndexOf((Card) this.controlCard)); + currentPlayer.tavern.add(this.controlCard); + this.controlCard.stopImpersonatingCard(); + + GameEvent event = new GameEvent(GameEvent.Type.CardSetAsideOnTavernMat, (MoveContext) context); + event.card = this.controlCard; + game.broadcastEvent(event); + } else { + // reset clone count + this.controlCard.cloneCount = 1; + } + } } From 01e8e3e1b8fbfdb921a90605a6278a30a673165c Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 2 Jan 2016 15:10:30 -0700 Subject: [PATCH 020/141] Adding support for calling cards that call after an action is resolved. Basic UI in place, may do more advanced UI later. Finishing Coin of the Realm. Fixing bug with +1 Buy token not working. --- androminion/res/values/card_styles.xml | 5 ++ androminion/res/values/strings-server.xml | 1 + .../com/mehtank/androminion/ui/CardView.java | 9 ++- .../com/mehtank/androminion/ui/Strings.java | 4 ++ vdom/src/com/vdom/core/ActionCardImpl.java | 55 +++++++++++++++++-- vdom/src/com/vdom/core/BasePlayer.java | 44 ++++++++++++++- .../com/vdom/core/CallableActionCardImpl.java | 13 +++++ vdom/src/com/vdom/core/CallableCard.java | 2 + .../vdom/core/CallableTreasureCardImpl.java | 13 +++++ vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/Game.java | 4 ++ vdom/src/com/vdom/core/IndirectPlayer.java | 17 +++++- vdom/src/com/vdom/core/Player.java | 1 + vdom/src/com/vdom/core/QuickPlayPlayer.java | 7 ++- 14 files changed, 166 insertions(+), 11 deletions(-) diff --git a/androminion/res/values/card_styles.xml b/androminion/res/values/card_styles.xml index 96bb50706..dce7e18b6 100644 --- a/androminion/res/values/card_styles.xml +++ b/androminion/res/values/card_styles.xml @@ -123,5 +123,10 @@ @color/cardReserve @color/cardVictory + + \ No newline at end of file diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 688a157af..de8bcfc3e 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -413,4 +413,5 @@ Select number of Wine Merchants, to discard from Tavern Gaining %1$s. Call card: + %1$s resolved. Call card: diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index c04dca840..a57ab5737 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -258,6 +258,8 @@ private static int getStyleForCard(MyCard c) { return R.style.CardView_Duration; } else if (c.isReserve && c.isVictory) { return R.style.CardView_Reserve_Victory; + } else if (c.isReserve && c.isTreasure) { + return R.style.CardView_Treasure_Reserve; } else if (c.isReserve) { return R.style.CardView_Reserve; } else if (c.isRuins) { @@ -651,6 +653,11 @@ else if (c.isTreasure) { cardType += " - " + context.getString(R.string.type_attack); } + + if (c.isReserve) + { + cardType += " - " + context.getString(R.string.type_reserve); + } if (c.isVictory) { @@ -665,7 +672,7 @@ else if (c.isTreasure) if (c.isPrize) { cardType += " - " + context.getString(R.string.type_prize); - } + } } else if (c.isVictory) { diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 4ec52596b..9a9b33e0b 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -518,6 +518,8 @@ private static int getOptionStartIndex(Card card, Object[] options) { return 1; } else if (optionString.equals(IndirectPlayer.OPTION_CALL_WHEN_GAIN)) { return 1; + } else if (optionString.equals(IndirectPlayer.OPTION_CALL_RESOLVE_ACTION)) { + return 1; } } if (card == null) @@ -562,6 +564,8 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { return getString(R.string.buy_overpay_by_potions); } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_CALL_WHEN_GAIN)) { return format(R.string.call_when_gain_query, getCardName(card)); + } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_CALL_RESOLVE_ACTION)) { + return format(R.string.call_resolve_action_query, getCardName(card)); } String cardName = getCardName(card); if (cardName.equals(getCardName(Cards.advisor))) { diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 60e39de7a..15b1047b9 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -249,7 +249,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneAction)) context.actions += 1; if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneBuy)) - context.buys += addBuys; + context.buys += 1; if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCoin)) context.addCoins(1); if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCard)) @@ -277,9 +277,56 @@ public void play(Game game, MoveContext context, boolean fromHand) { // test if any prince card left the play currentPlayer.princeCardLeftThePlay(currentPlayer); - } - - protected void additionalCardActions(Game game, MoveContext context, Player currentPlayer) { + + // check for cards to call after resolving action + boolean isActionInPlay = isInPlay(currentPlayer); + ArrayList callableCards = new ArrayList(); + CallableCard toCall = null; + for (Card c : currentPlayer.tavern) { + if (c.behaveAsCard() instanceof CallableCard) { + CallableCard card = (CallableCard)(c.behaveAsCard()); + if (!card.isCallableWhenActionResolved() || (card.doesActionStillNeedToBeInPlay() && !isActionInPlay)) + continue; + callableCards.add((CallableCard) c); + } + } + if (!callableCards.isEmpty()) { + Collections.sort(callableCards, new Util.CardCostComparator()); + do { + toCall = null; + // we want null entry at the end for None + CallableCard[] cardsAsArray = callableCards.toArray(new CallableCard[callableCards.size() + 1]); + //ask player which card to call + toCall = currentPlayer.controlPlayer.call_whenActionResolveCardToCall(context, this, cardsAsArray); + if (toCall != null && callableCards.contains(toCall)) { + callableCards.remove(toCall); + toCall.callWhenActionResolved(context, this); + } + // loop while we still have cards to call + // NOTE: we have a hack here to prevent asking for duplicate calls on an unused Royal Carriage + // since technically you can ask for more and action re-played by royal carriage will ask as well + } while (toCall != null && toCall.equals(Cards.coinOfTheRealm) && !callableCards.isEmpty()); + } + } + + private boolean isInPlay(Player currentPlayer) { + for (Card c : currentPlayer.playedCards) { + if (this == c) + return true; + } + for (Card c : currentPlayer.nextTurnCards) { + if (c instanceof ActionCardImpl && !((ActionCardImpl)c).trashAfterPlay && this == c) + if (this == c) + return true; + } + for (Card c : currentPlayer.playedByPrince) { + if (this == c) + return true; + } + return false; + } + + protected void additionalCardActions(Game game, MoveContext context, Player currentPlayer) { switch (this.getType()) { case BandOfMisfits: bandOfMisfits(game, context, currentPlayer); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 99724332c..fc5ff8f70 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3224,8 +3224,50 @@ public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard return possibleCards[0]; return null; } + + public CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards) { + // Check coin of the Realm first + boolean hasMoreActionsLeft = false; + for (Card c : getHand()) { + if (c instanceof ActionCard) { + hasMoreActionsLeft = true; + } + } + for (CallableCard c : possibleCards) { + if (c == null) continue; + if (c.equals(Cards.coinOfTheRealm) && context.actions == 0 && hasMoreActionsLeft) { + return c; + } + } + // Royal Carriage our strongest action card + Card bestAction = getBestActionCard(getHand(), context); + if (bestAction != null) { + for (CallableCard c : possibleCards) { + if (c == null) continue; + if (c.behaveAsCard().equals(Cards.royalCarriage) && resolvedAction.equals(bestAction)) { + return c; + } + } + } + return null; + } - @Override + private Card getBestActionCard(CardList hand, MoveContext context) { + int highestCost = -1; + Card bestCard = null; + for (Card c : getDistinctCards()) { + if (c instanceof ActionCard) { + int cost = c.getCost(context); + if (cost > highestCost) { + highestCost = cost; + bestCard = c; + } + } + } + return bestCard; + } + + @Override public Card[] gear_cardsToSetAside(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index ae99d08a0..e0ced8adc 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -9,6 +9,7 @@ public class CallableActionCardImpl extends ActionCardImpl implements CallableCa private static final long serialVersionUID = 1L; protected boolean callableWhenCardGained; protected boolean callableWhenActionResolved; + protected boolean actionStillNeedsToBeInPlay; protected boolean callableWhenTurnStarts; protected int callableWhenCardGainedMaxCost = -1; @@ -16,6 +17,7 @@ protected CallableActionCardImpl(Builder builder) { super(builder); callableWhenCardGained = builder.callableWhenCardGained; callableWhenActionResolved = builder.callableWhenActionResolved; + actionStillNeedsToBeInPlay = builder.actionStillNeedsToBeInPlay; callableWhenTurnStarts = builder.callableWhenTurnStarts; callableWhenCardGainedMaxCost = builder.callableWhenCardGainedMaxCost; } @@ -32,6 +34,10 @@ public boolean isCallableWhenActionResolved() { return callableWhenActionResolved; } + public boolean doesActionStillNeedToBeInPlay() { + return actionStillNeedsToBeInPlay; + } + public boolean isCallableWhenTurnStarts() { return callableWhenTurnStarts; } @@ -39,6 +45,7 @@ public boolean isCallableWhenTurnStarts() { public static class Builder extends ActionCardImpl.Builder { protected boolean callableWhenCardGained; protected boolean callableWhenActionResolved; + protected boolean actionStillNeedsToBeInPlay; protected boolean callableWhenTurnStarts; protected int callableWhenCardGainedMaxCost; @@ -55,6 +62,12 @@ public Builder callWhenActionResolved() { callableWhenActionResolved = true; return this; } + + public Builder callWhenActionResolved(boolean mustBeInPlay) { + callableWhenActionResolved = true; + actionStillNeedsToBeInPlay = mustBeInPlay; + return this; + } public Builder callWhenGainCard(int maxCost) { callableWhenCardGained = true; diff --git a/vdom/src/com/vdom/core/CallableCard.java b/vdom/src/com/vdom/core/CallableCard.java index c62f4687b..f2a55032d 100644 --- a/vdom/src/com/vdom/core/CallableCard.java +++ b/vdom/src/com/vdom/core/CallableCard.java @@ -9,6 +9,8 @@ public interface CallableCard extends Card { public boolean isCallableWhenActionResolved(); + public boolean doesActionStillNeedToBeInPlay(); + public boolean isCallableWhenTurnStarts(); public void callWhenCardGained(MoveContext context, Card cardToGain); diff --git a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java index bf4aae61a..59fa69989 100644 --- a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java +++ b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java @@ -8,6 +8,7 @@ public class CallableTreasureCardImpl extends TreasureCardImpl implements Callab private static final long serialVersionUID = 1L; protected boolean callableWhenCardGained; protected boolean callableWhenActionResolved; + protected boolean actionStillNeedsToBeInPlay; protected boolean callableWhenTurnStarts; protected int callableWhenCardGainedMaxCost = -1; @@ -15,6 +16,7 @@ protected CallableTreasureCardImpl(Builder builder) { super(builder); callableWhenCardGained = builder.callableWhenCardGained; callableWhenActionResolved = builder.callableWhenActionResolved; + actionStillNeedsToBeInPlay = builder.actionStillNeedsToBeInPlay; callableWhenTurnStarts = builder.callableWhenTurnStarts; callableWhenCardGainedMaxCost = builder.callableWhenCardGainedMaxCost; } @@ -31,6 +33,10 @@ public boolean isCallableWhenActionResolved() { return callableWhenActionResolved; } + public boolean doesActionStillNeedToBeInPlay() { + return actionStillNeedsToBeInPlay; + } + public boolean isCallableWhenTurnStarts() { return callableWhenTurnStarts; } @@ -39,6 +45,7 @@ public static class Builder extends TreasureCardImpl.Builder { protected boolean callableWhenCardGained; protected boolean callableWhenActionResolved; + protected boolean actionStillNeedsToBeInPlay; protected boolean callableWhenTurnStarts; protected int callableWhenCardGainedMaxCost; @@ -55,6 +62,12 @@ public Builder callWhenActionResolved() { callableWhenActionResolved = true; return this; } + + public Builder callWhenActionResolved(boolean mustBeInPlay) { + callableWhenActionResolved = true; + actionStillNeedsToBeInPlay = mustBeInPlay; + return this; + } public Builder callWhenGainCard(int maxCost) { callableWhenCardGained = true; diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 02341ee98..457ed1ff0 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -723,7 +723,7 @@ public enum Type { actionCardsAdventures.add(ratcatcher = new CallableActionCardImpl.Builder(Cards.Type.Ratcatcher, 2).callWhenTurnStarts().addCards(1).addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand.").expansion("Adventures").build()); actionCardsAdventures.add(raze = new ActionCardImpl.Builder(Cards.Type.Raze, 2).addActions(1).description("Trash this or a card from your hand. Look at a number of cards from the top of your deck equal to the cost in Coins of the trashed card. Put one into your hand and discard the rest.").expansion("Adventures").build()); actionCardsAdventures.add(relic = new TreasureCardImpl.Builder(Cards.Type.Relic, 5, 2).attack().description("When you play this, each other player puts his -1 Card token on his deck.").expansion("Adventures").build()); - actionCardsAdventures.add(royalCarriage = new CallableActionCardImpl.Builder(Cards.Type.RoyalCarriage, 5).callWhenActionResolved().addActions(1).isReserve().description("Put this on your Tavern mat. ~ Directly after resolving an Action, if it's still in play, you may call this, to replay that Action.").expansion("Adventures").build()); + actionCardsAdventures.add(royalCarriage = new CallableActionCardImpl.Builder(Cards.Type.RoyalCarriage, 5).callWhenActionResolved(true).addActions(1).isReserve().description("Put this on your Tavern mat. ~ Directly after resolving an Action, if it's still in play, you may call this, to replay that Action.").expansion("Adventures").build()); actionCardsAdventures.add(storyteller = new ActionCardImpl.Builder(Cards.Type.Storyteller, 5).addGold(1).addActions(1).description("Play up to 3 Treasures from your hand. Pay all of your Coins; +1 Card per Coin paid.").expansion("Adventures").build()); actionCardsAdventures.add(swampHag = new ActionDurationCardImpl.Builder(Cards.Type.SwampHag, 5).addGoldNextTurn(3).attack().description("Until your next turn, when any other player buys a card, he gains a Curse.").expansion("Adventures").build()); actionCardsAdventures.add(transmogrify = new CallableActionCardImpl.Builder(Cards.Type.Transmogrify, 4).callWhenTurnStarts().addActions(1).isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to trash a card from your hand, gain a card costing up to 1 Coin more than it, and put that card into your hand.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index ed9d5a25d..9b6467c71 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -2423,6 +2423,10 @@ public void gameEvent(GameEvent event) { } } + // check for when-gain callable cards + // NOTE: Technically this should be done in a loop, as you can call multiple cards for one when-gain. + // However, since the only card here, Duplicate, will trigger another on-gain anyway + // we don't need to. ArrayList callableCards = new ArrayList(); for (Card c : player.tavern) { if (c.behaveAsCard() instanceof CallableCard) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index d938f6f7b..2bc340145 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2599,8 +2599,7 @@ public Card artificer_cardToObtain(MoveContext context, int cost) { } @Override - public CallableCard call_whenGainCardToCall(MoveContext context, - Card gainedCard, CallableCard[] possibleCards) { + public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards) { if(context.isQuickPlay() && shouldAutoPlay_call_whenGainCardToCall(context, gainedCard, possibleCards)) { return super.call_whenGainCardToCall(context, gainedCard, possibleCards); } @@ -2612,6 +2611,20 @@ public CallableCard call_whenGainCardToCall(MoveContext context, } return possibleCards[selectOption(context, gainedCard, options)]; } + + @Override + public CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards) { + if(context.isQuickPlay() && shouldAutoPlay_call_whenActionResolveCardToCall(context, resolvedAction, possibleCards)) { + return super.call_whenActionResolveCardToCall(context, resolvedAction, possibleCards); + } + + Object[] options = new Object[1 + possibleCards.length]; + options[0] = OPTION_CALL_RESOLVE_ACTION; + for (int i = 0; i < possibleCards.length; i++) { + options[i + 1] = possibleCards[i]; + } + return possibleCards[selectOption(context, resolvedAction, options)]; + } @Override public Card[] gear_cardsToSetAside(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 91ca10f65..9d41e5ed3 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1721,6 +1721,7 @@ public ArrayList getActionsInHand() { public abstract Card[] artificer_cardsToDiscard(MoveContext context); public abstract Card artificer_cardToObtain(MoveContext context, int cost); public abstract CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards); + public abstract CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards); public abstract Card[] gear_cardsToSetAside(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); public abstract Card messenger_cardToObtain(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 85649119f..134744ab1 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -821,8 +821,11 @@ public boolean shouldAutoPlay_artificer_cardToObtain(MoveContext context, int co return false; } - public boolean shouldAutoPlay_call_whenGainCardToCall(MoveContext context, - Card gainedCard, CallableCard[] possibleCards) { + public boolean shouldAutoPlay_call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards) { + return false; + } + + public boolean shouldAutoPlay_call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedCard, CallableCard[] possibleCards) { return false; } From a856e85e527da4e2b18237206ff2a09ece729179 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 2 Jan 2016 16:47:45 -0700 Subject: [PATCH 021/141] Implmenting Royal Carriage. --- vdom/src/com/vdom/core/BasePlayer.java | 1 + .../com/vdom/core/CallableActionCardImpl.java | 31 +++++++++++++++++-- vdom/src/com/vdom/core/CallableCard.java | 3 +- .../vdom/core/CallableTreasureCardImpl.java | 5 ++- vdom/src/com/vdom/core/Game.java | 1 + vdom/src/com/vdom/core/RemotePlayer.java | 2 +- 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index fc5ff8f70..e8cf50371 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3220,6 +3220,7 @@ public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard if (c.equals(gainedCard)) return null; } + //TODO: duplicate only good stuff if (possibleCards.length > 0) return possibleCards[0]; return null; diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index e0ced8adc..9acb3da54 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -2,6 +2,7 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; +import com.vdom.api.DurationCard; import com.vdom.api.GameEvent; public class CallableActionCardImpl extends ActionCardImpl implements CallableCard { @@ -94,6 +95,7 @@ protected void copyValues(CallableActionCardImpl c) { c.callableWhenActionResolved = callableWhenActionResolved; c.callableWhenTurnStarts = callableWhenTurnStarts; c.callableWhenCardGainedMaxCost = callableWhenCardGainedMaxCost; + c.actionStillNeedsToBeInPlay = actionStillNeedsToBeInPlay; } protected CallableActionCardImpl() { @@ -132,7 +134,7 @@ public void callWhenCardGained(MoveContext context, Card cardToGain) { finishCall(context); } - public void callWhenActionResolved(MoveContext context, Card resolvedAction) { + public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction) { if (!callableWhenActionResolved) return; if (!call(context)) return; Game game = context.game; @@ -203,8 +205,33 @@ private void ratcatcher(MoveContext context, Game game, Player currentPlayer) { } private void royalCarriage(Card resolvedAction, MoveContext context, Game game, Player currentPlayer) { - // TODO Auto-generated method stub + ActionCardImpl cardToPlay = (ActionCardImpl) resolvedAction; + context.freeActionInEffect++; + + cardToPlay.cloneCount += 1; + cardToPlay.numberTimesAlreadyPlayed = 1; + cardToPlay.play(game, context, false); + cardToPlay.numberTimesAlreadyPlayed = 0; //TODO: not sure if this is right + context.freeActionInEffect--; + // If the cardToPlay was a knight, and was trashed, reset clonecount + if (cardToPlay.isKnight() && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { + cardToPlay.cloneCount = 1; + } + + if (cardToPlay instanceof DurationCard && !cardToPlay.equals(Cards.tactician)) { + // Need to move royal carriage card to NextTurnCards first + // (but does not play) + if (!this.controlCard.movedToNextTurnPile) { + this.controlCard.movedToNextTurnPile = true; + int idx = currentPlayer.playedCards.lastIndexOf(this.controlCard); + int ntidx = currentPlayer.nextTurnCards.size() - 1; + if (idx >= 0 && ntidx >= 0) { + currentPlayer.playedCards.remove(idx); + currentPlayer.nextTurnCards.add(ntidx, this.controlCard); + } + } + } } private void teacher(MoveContext context, Game game, Player currentPlayer) { diff --git a/vdom/src/com/vdom/core/CallableCard.java b/vdom/src/com/vdom/core/CallableCard.java index f2a55032d..8e1faa2b4 100644 --- a/vdom/src/com/vdom/core/CallableCard.java +++ b/vdom/src/com/vdom/core/CallableCard.java @@ -1,5 +1,6 @@ package com.vdom.core; +import com.vdom.api.ActionCard; import com.vdom.api.Card; public interface CallableCard extends Card { @@ -15,7 +16,7 @@ public interface CallableCard extends Card { public void callWhenCardGained(MoveContext context, Card cardToGain); - public void callWhenActionResolved(MoveContext context, Card resolvedAction); + public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction); public void callAtStartOfTurn(MoveContext context); } diff --git a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java index 59fa69989..73dbf5764 100644 --- a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java +++ b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java @@ -1,5 +1,6 @@ package com.vdom.core; +import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.GameEvent; @@ -94,6 +95,7 @@ protected void copyValues(CallableTreasureCardImpl c) { c.callableWhenActionResolved = callableWhenActionResolved; c.callableWhenTurnStarts = callableWhenTurnStarts; c.callableWhenCardGainedMaxCost = callableWhenCardGainedMaxCost; + c.actionStillNeedsToBeInPlay = actionStillNeedsToBeInPlay; } protected CallableTreasureCardImpl() { @@ -107,6 +109,7 @@ private boolean call(MoveContext context) { currentPlayer.playedCards.add(this.controlCard); GameEvent event = new GameEvent(GameEvent.Type.CallingCard, (MoveContext) context); event.card = this.controlCard; + event.newCard = true; context.game.broadcastEvent(event); return true; } @@ -127,7 +130,7 @@ public void callWhenCardGained(MoveContext context, Card cardToGain) { finishCall(context); } - public void callWhenActionResolved(MoveContext context, Card resolvedAction) { + public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction) { if (!callableWhenActionResolved) return; if (!call(context)) return; Game game = context.game; diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 9b6467c71..4ac35bf64 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -872,6 +872,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { || card.equals(Cards.disciple) || card.equals(Cards.kingsCourt) || card.equals(Cards.procession) + || card.equals(Cards.royalCarriage) || card.equals(Cards.bandOfMisfits)) { if(!player.nextTurnCards.isEmpty()) { diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index dc210c1cb..4ecf127b0 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -637,7 +637,7 @@ public void gameEvent(GameEvent event) { extras.add(islandSize); int nativeVillageSize = event.player.nativeVillage.size(); extras.add(nativeVillageSize); - } else if (isPlayersTurn(event) && event.getType() == Type.PlayingAction || event.getType() == Type.PlayingDurationAction) { + } else if (isPlayersTurn(event) && event.getType() == Type.PlayingAction || event.getType() == Type.PlayingDurationAction || event.getType() == Type.CallingCard) { playedCards.add(event.getCard()); playedCardsNew.add(event.newCard); } else if (isPlayersTurn(event) && event.getType() == Type.PlayingCoin) { From 904facbf0234083e344c98548ea6912d3b0db614 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 2 Jan 2016 16:50:45 -0700 Subject: [PATCH 022/141] Making called cards appear not shaded in UI. --- vdom/src/com/vdom/core/CallableActionCardImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 9acb3da54..379d22d61 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -109,6 +109,7 @@ private boolean call(MoveContext context) { currentPlayer.playedCards.add(this.controlCard); GameEvent event = new GameEvent(GameEvent.Type.CallingCard, (MoveContext) context); event.card = this.controlCard; + event.newCard = true; context.game.broadcastEvent(event); return true; } From 035926e82531d8475be0f040c52bd153de0b2724 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 2 Jan 2016 19:57:11 -0700 Subject: [PATCH 023/141] Can call cards at start of turn. Still missing interleaving those with other start-of-turn actions. Implemented Teacher. --- androminion/res/values/strings-server.xml | 2 + .../com/mehtank/androminion/ui/Strings.java | 5 ++ vdom/src/com/vdom/core/BasePlayer.java | 78 ++++++++++++++++++- .../com/vdom/core/CallableActionCardImpl.java | 1 - vdom/src/com/vdom/core/Cards.java | 2 +- vdom/src/com/vdom/core/Game.java | 30 +++++++ vdom/src/com/vdom/core/IndirectPlayer.java | 14 ++++ vdom/src/com/vdom/core/Player.java | 1 + vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 + 9 files changed, 131 insertions(+), 6 deletions(-) diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index de8bcfc3e..f8d91dd6f 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -409,9 +409,11 @@ %1$s Swamp Hag in play %1$s Swamp Hags in play Exchange it for %1$s + move your token to (without your tokens on it). [Teacher] Discard from Tavern Select number of Wine Merchants, to discard from Tavern Gaining %1$s. Call card: %1$s resolved. Call card: + Start of turn. Call card: diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 9a9b33e0b..07437d5bf 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -520,6 +520,8 @@ private static int getOptionStartIndex(Card card, Object[] options) { return 1; } else if (optionString.equals(IndirectPlayer.OPTION_CALL_RESOLVE_ACTION)) { return 1; + } else if (optionString.equals(IndirectPlayer.OPTION_START_TURN_EFFECT)) { + return 1; } } if (card == null) @@ -566,6 +568,8 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { return format(R.string.call_when_gain_query, getCardName(card)); } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_CALL_RESOLVE_ACTION)) { return format(R.string.call_resolve_action_query, getCardName(card)); + } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_START_TURN_EFFECT)) { + return getString(R.string.call_start_turn_query); } String cardName = getCardName(card); if (cardName.equals(getCardName(Cards.advisor))) { @@ -1244,6 +1248,7 @@ private static void initActionStrings() { actionStringMap.put(getCardName(Cards.training), getString(R.string.part_move_token_plus_one_coin)); actionStringMap.put(getCardName(Cards.university), getString(R.string.university_part)); actionStringMap.put(getCardName(Cards.urchin), getString(R.string.urchin_keep)); + actionStringMap.put(getCardName(Cards.teacher), getString(R.string.teacher_move_token)); } public static String getActionCardText(SelectCardOptions sco) { diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index e8cf50371..5d02c1767 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -149,6 +149,9 @@ protected int getCoinEstimate(MoveContext context) { } coin += bankcount * (treasurecards + venturecount) - (bankcount*bankcount + bankcount) / 2; coin += context.player.getGuildsCoinTokenCount(); + coin += context.getCoins(); + + //TODO: estimate coin to get from actions in hand return coin; } @@ -3252,6 +3255,69 @@ public CallableCard call_whenActionResolveCardToCall(MoveContext context, Action } return null; } + + @Override + public CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCard[] possibleCards) { + CardList hand = context.getPlayer().getHand(); + int coins = getCoinEstimate(context); + for (CallableCard c : possibleCards) { + if (c == null) continue; + if (c.equals(Cards.ratcatcher) && + pickOutCard(hand, getTrashCards()) != null) { + return c; + } else if (c.equals(Cards.teacher)) { + if (!getUnplacedTokens(context).isEmpty()) { + return c; + } + } else if (c.equals(Cards.transmogrify)) { + //TODO: when to call Transmogrify - currently always + return c; + } + } + + // Guide logic - want to call Guide after any Ratcatchers + for (CallableCard c : possibleCards) { + if (c == null) continue; + if (c.equals(Cards.guide)) { + if (coins < Cards.gold.getCost(context) && hand.contains(Cards.tunnel)) { + return c; + } + + //use guide to cycle faster if have Travellers in deck + boolean handHasTraveller = false; + for (Card handCard : hand) { + if (handCard.isTraveller()) { + handHasTraveller = true; + break; + } + } + if (!handHasTraveller) { + for (Card card : context.getPlayer().getDistinctCards()) { + if (card.isTraveller()) { + return c; + } + } + } + + //use guide if have bad hand + //TODO: better rules around what constitutes a bad hand + if (coins < 4 || hand.size() < 5) { + return c; + } + } + } + + //Transmogrify - always call after Guide + for (CallableCard c : possibleCards) { + if (c == null) continue; + if (c.equals(Cards.transmogrify)) { + //TODO: when to call Transmogrify - currently always + return c; + } + } + + return null; + } private Card getBestActionCard(CardList hand, MoveContext context) { int highestCost = -1; @@ -3376,6 +3442,13 @@ public Card raze_cardToKeep(MoveContext context, Card[] cards) { @Override public PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context) { //get a token that hasn't been used yet if possible + List validTokens = getUnplacedTokens(context); + if (validTokens.size() > 0) + return validTokens.get(0); + return PlayerSupplyToken.PlusOneCard; + } + + private List getUnplacedTokens(MoveContext context) { ArrayList validTokens = new ArrayList(); ArrayList unavailableTokens = new ArrayList(); validTokens.add(PlayerSupplyToken.PlusOneCard); @@ -3392,10 +3465,7 @@ public PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context) { for (PlayerSupplyToken token : unavailableTokens) validTokens.remove(token); - - if (validTokens.size() > 0) - return validTokens.get(0); - return PlayerSupplyToken.PlusOneCard; + return validTokens; } @Override diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 379d22d61..8649a820e 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -245,7 +245,6 @@ private void teacher(MoveContext context, Game game, Player currentPlayer) { && game.getPlayerSupplyTokens(c, currentPlayer).size() == 0) { numFreePiles++; lastFreePile = (ActionCard) c; - break; } } if (numFreePiles == 0) diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 457ed1ff0..107c65a6f 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -759,7 +759,7 @@ public enum Type { nonSupplyCards.add(fugitive = new ActionCardImpl.Builder(Cards.Type.Fugitive , 4).addCards(2).addActions(1).isTraveller().description("Discard a card. ~ When you discard this from play, you may exchange it for a Disciple.").expansion("Adventures").build()); nonSupplyCards.add(hero = new ActionCardImpl.Builder(Cards.Type.Hero , 5).addGold(2).isTraveller().description("Gain a Treasure - When you discard this from play, you may exchange it for a Champion.").expansion("Adventures").build()); nonSupplyCards.add(soldier = new ActionCardImpl.Builder(Cards.Type.Soldier , 3).addGold(2).isTraveller().attack().description("+1 Coin per other Attack you have in play. Each other player with 4 or more cards in hand discards a card. ~ When you discard this from play, you may exchange it for a Fugitive.").expansion("Adventures").build()); - nonSupplyCards.add(teacher = new CallableActionCardImpl.Builder(Cards.Type.Teacher , 6).callWhenTurnStarts().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 Coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus).").expansion("Adventures").build()); + nonSupplyCards.add(teacher = new CallableActionCardImpl.Builder(Cards.Type.Teacher , 6).callWhenTurnStarts().isReserve().description("Put this on your Tavern mat. ~ At the start of your turn, you may call this, to move your +1 Card, +1 Action, +1 Buy, or +1 Coin token to an Action Supply pile you have no tokens on (when you play a card from that pile, you first get that bonus).").expansion("Adventures").build()); nonSupplyCards.add(treasureHunter = new ActionCardImpl.Builder(Cards.Type.TreasureHunter , 3).addGold(1).addActions(1).isTraveller().description("Gain a Silver per card the player to your right gained in his last turn. ~ When you discard this from play, you may exchange it for a Warrior.").expansion("Adventures").build()); nonSupplyCards.add(warrior = new ActionCardImpl.Builder(Cards.Type.Warrior , 4).addCards(2).isTraveller().attack().description("For each Traveller you have in play (including this), each other player discards the top card of his deck and trashes it if it costs 3 or 4 Coins. ~ When you discard this from play, you may exchange it for a Hero.").expansion("Adventures").build()); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 4ac35bf64..47a69c3ff 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -901,6 +901,36 @@ protected void playerBeginTurn(Player player, MoveContext context) { while (!staysInPlayCards.isEmpty()) { player.nextTurnCards.add(staysInPlayCards.remove(0)); } + + //TODO: Dominionator - integrate this with other start of turn logic + // Will require tracking duration effects independent of cards + + //check for start-of-turn callable cards + ArrayList callableCards = new ArrayList(); + CallableCard toCall = null; + for (Card c : player.tavern) { + if (c.behaveAsCard() instanceof CallableCard) { + CallableCard card = (CallableCard)(c.behaveAsCard()); + if (!card.isCallableWhenTurnStarts()) + continue; + callableCards.add((CallableCard) c); + } + } + if (!callableCards.isEmpty()) { + Collections.sort(callableCards, new Util.CardCostComparator()); + do { + toCall = null; + // we want null entry at the end for None + CallableCard[] cardsAsArray = callableCards.toArray(new CallableCard[callableCards.size() + 1]); + //ask player which card to call + toCall = player.controlPlayer.call_whenTurnStartCardToCall(context, cardsAsArray); + if (toCall != null && callableCards.contains(toCall)) { + callableCards.remove(toCall); + toCall.callAtStartOfTurn(context); + } + // loop while we still have cards to call + } while (toCall != null && !callableCards.isEmpty()); + } } private static void printStats(HashMap wins, int gameCount, String gameType) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 2bc340145..3a8eb7b7f 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2625,6 +2625,20 @@ public CallableCard call_whenActionResolveCardToCall(MoveContext context, Action } return possibleCards[selectOption(context, resolvedAction, options)]; } + + @Override + public CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCard[] possibleCards) { + if(context.isQuickPlay() && shouldAutoPlay_call_whenTurnStartCardToCall(context, possibleCards)) { + return super.call_whenTurnStartCardToCall(context, possibleCards); + } + + Object[] options = new Object[1 + possibleCards.length]; + options[0] = OPTION_START_TURN_EFFECT; + for (int i = 0; i < possibleCards.length; i++) { + options[i + 1] = possibleCards[i]; + } + return possibleCards[selectOption(context, null, options)]; + } @Override public Card[] gear_cardsToSetAside(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 9d41e5ed3..1c4f20907 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1722,6 +1722,7 @@ public ArrayList getActionsInHand() { public abstract Card artificer_cardToObtain(MoveContext context, int cost); public abstract CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards); public abstract CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards); + public abstract CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCard[] possibleCards); public abstract Card[] gear_cardsToSetAside(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); public abstract Card messenger_cardToObtain(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 134744ab1..2cb6654f4 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -829,6 +829,10 @@ public boolean shouldAutoPlay_call_whenActionResolveCardToCall(MoveContext conte return false; } + public boolean shouldAutoPlay_call_whenTurnStartCardToCall(MoveContext context, CallableCard[] possibleCards) { + return false; + } + public boolean shouldAutoPlay_messenger_shouldDiscardDeck(MoveContext context, Card responsible) { return true; } From 24d39461c2a3c1748002449d459faa59ae22f7ec Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 3 Jan 2016 15:36:05 -0700 Subject: [PATCH 024/141] Implmenting Adventures event: Ball --- androminion/res/values/strings-cards.xml | 4 ++-- .../src/com/mehtank/androminion/ui/Strings.java | 1 + vdom/src/com/vdom/core/BasePlayer.java | 4 ++++ vdom/src/com/vdom/core/CardSet.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 17 +++++++++++++++++ vdom/src/com/vdom/core/IndirectPlayer.java | 10 ++++++++++ vdom/src/com/vdom/core/Player.java | 1 + vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 ++++ 8 files changed, 40 insertions(+), 3 deletions(-) diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index 9780cd7ef..7ed918f6e 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -557,11 +557,11 @@ Alms Once per turn: If you have no Treasures in play, gain a card costing up to 4 Coins. Ball - Take your -1 coin token. Gain 2 cards each costing up to 4 Coins. + Take your -1 Coin token. Gain 2 cards each costing up to 4 Coins. Bonfire Trash up to 2 cards you have in play. Borrow - Once per turn: If your -1 Card token isn\'t on your deck, put it there and +1 coin. + Once per turn: If your -1 Card token isn\'t on your deck, put it there and +1 Coin. Expedition Draw 2 extra cards for your next hand. Ferry diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 07437d5bf..05d59895e 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1214,6 +1214,7 @@ private static void initActionStrings() { getCardName(Cards.transmogrify), /*Adventures Events*/ getCardName(Cards.alms), + getCardName(Cards.ball), getCardName(Cards.seaway) )); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 5d02c1767..bec820eef 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3548,6 +3548,10 @@ public int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTo public Card alms_cardToObtain(MoveContext context) { return bestCardInPlay(context, 4, true); } + @Override + public Card ball_cardToObtain(MoveContext context) { + return bestCardInPlay(context, 4, true); + } public Card[] bonfire_cardsToTrash(MoveContext context) { return pickOutCards(context.getPlayer().playedCards, 2, getTrashCards()); diff --git a/vdom/src/com/vdom/core/CardSet.java b/vdom/src/com/vdom/core/CardSet.java index 97719fc16..dcb17b380 100644 --- a/vdom/src/com/vdom/core/CardSet.java +++ b/vdom/src/com/vdom/core/CardSet.java @@ -224,7 +224,7 @@ public boolean isRandom() { CardSetMap.put(GameType.DecisionsDecisions, new CardSet(new Card[]{Cards.merchantGuild, Cards.candlestickMaker, Cards.masterpiece, Cards.taxman, Cards.butcher, Cards.bridge, Cards.pawn, Cards.miningVillage, Cards.upgrade, Cards.duke}, null)); /*frr18 AdventureTest*/ - CardSetMap.put(GameType.AdventureTest, new CardSet(new Card[]{Cards.moat, Cards.bridgeTroll, Cards.masquerade, Cards.save, Cards.wharf, Cards.bonfire, Cards.woodcutter, Cards.borrow, Cards.throneRoom, Cards.contraband, Cards.alms, Cards.raid}, null)); + CardSetMap.put(GameType.AdventureTest, new CardSet(new Card[]{Cards.ratcatcher, Cards.bridgeTroll, Cards.amulet, Cards.guide, Cards.save, Cards.transmogrify, Cards.workersVillage, Cards.peasant, Cards.borrow, Cards.throneRoom, Cards.contraband, Cards.expedition, Cards.raid, Cards.militia, Cards.ferry, Cards.embargo, Cards.lostArts, Cards.training, Cards.plan, Cards.pathfinding, Cards.seaway, Cards.duplicate}, null)); CardSetMap.put(GameType.GentleIntro, new CardSet(new Card[] { Cards.amulet, Cards.distantLands, Cards.dungeon, Cards.duplicate, Cards.giant, Cards.hireling, Cards.port, Cards.ranger, Cards.ratcatcher, Cards.treasureTrove, Cards.scoutingParty}, null)); CardSetMap.put(GameType.ExpertIntro, new CardSet(new Card[] { Cards.caravanGuard, Cards.coinOfTheRealm, Cards.hauntedWoods, Cards.lostCity, Cards.magpie, Cards.peasant, Cards.raze, Cards.swampHag, Cards.transmogrify, Cards.wineMerchant, Cards.mission, Cards.plan}, null)); CardSetMap.put(GameType.LevelUp, new CardSet(new Card[] { Cards.dungeon, Cards.gear, Cards.guide, Cards.lostCity, Cards.miser, Cards.market, Cards.militia, Cards.spy, Cards.throneRoom, Cards.workshop, Cards.training}, null)); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 9371a1e40..3bdb4dc96 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -58,6 +58,9 @@ public void isBuying(MoveContext context) { case Alms: alms(context); break; + case Ball: + ball(context); + break; case Bonfire: bonfire(context); break; @@ -118,6 +121,20 @@ public void alms(MoveContext context) { context.cantBuy.add(this); //once per turn } + public void ball(MoveContext context) { + Player player = context.getPlayer(); + player.setMinusOneCoinToken(true, context); + for (int i = 0; i < 2; ++i) { + Card card = player.controlPlayer.ball_cardToObtain(context); + if (card != null) { + // check cost + if (card.getCost(context) <= 4) { + player.gainNewCard(card, this, context); + } + } + } + } + private void bonfire(MoveContext context) { Card[] cards = context.player.controlPlayer.bonfire_cardsToTrash(context); if (cards != null) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 3a8eb7b7f..160109853 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2788,6 +2788,16 @@ public Card alms_cardToObtain(MoveContext context) { .setCardResponsible(Cards.alms).setActionType(ActionType.GAIN); return getFromTable(context, sco); } + + @Override + public Card ball_cardToObtain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_ball_cardToObtain(context)) { + return super.ball_cardToObtain(context); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) + .setCardResponsible(Cards.ball).setActionType(ActionType.GAIN); + return getFromTable(context, sco); + } @Override public Card[] bonfire_cardsToTrash(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 1c4f20907..4b32e57b2 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1743,6 +1743,7 @@ public ArrayList getActionsInHand() { // /////////////////////////////////////////////// public abstract Card alms_cardToObtain(MoveContext context); + public abstract Card ball_cardToObtain(MoveContext context); public abstract Card[] bonfire_cardsToTrash(MoveContext context); public abstract ActionCard ferry_actionCardPileToHaveToken(MoveContext context); public abstract ActionCard lostArts_actionCardPileToHaveToken(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 2cb6654f4..2a2d2db33 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -892,6 +892,10 @@ public boolean shouldAutoPlay_alms_cardToObtain(MoveContext context) { return false; } + public boolean shouldAutoPlay_ball_cardToObtain(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_ferry_actionCardPileToHaveToken(MoveContext context) { return false; } From 4e14c06e469ccf01a7dde74185188a59e7b11ed2 Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 4 Jan 2016 21:41:29 -0700 Subject: [PATCH 025/141] Adding changes from @androminionfan fork Adding Pilgrmage. Adding TravellingFair Adding Trade KC + gear fixed. swindler: you must not select events to swindle stonemason: if trashing golem you can get a card for 4 coins Various german translations --- androminion/res/values-de/strings-cards.xml | 24 ++++---- androminion/res/values-de/strings-server.xml | 4 +- androminion/res/values/strings-server.xml | 2 + .../com/mehtank/androminion/ui/DeckView.java | 1 - .../com/mehtank/androminion/ui/Strings.java | 14 ++++- vdom/src/com/vdom/api/GameEvent.java | 9 +-- .../src/com/vdom/comms/SelectCardOptions.java | 12 +++- vdom/src/com/vdom/core/BasePlayer.java | 38 ++++++++++++- vdom/src/com/vdom/core/EventCardImpl.java | 55 +++++++++++++++++++ vdom/src/com/vdom/core/Game.java | 12 ++-- vdom/src/com/vdom/core/IndirectPlayer.java | 46 +++++++++++++--- vdom/src/com/vdom/core/MoveContext.java | 1 + vdom/src/com/vdom/core/Player.java | 15 ++++- vdom/src/com/vdom/core/QuickPlayPlayer.java | 10 +++- vdom/src/com/vdom/core/UI.java | 2 +- .../com/vdom/players/VDomPlayerPatrick.java | 3 + 16 files changed, 206 insertions(+), 42 deletions(-) diff --git a/androminion/res/values-de/strings-cards.xml b/androminion/res/values-de/strings-cards.xml index 506585106..3fd00dee2 100644 --- a/androminion/res/values-de/strings-cards.xml +++ b/androminion/res/values-de/strings-cards.xml @@ -244,7 +244,7 @@ Abenteuer Wenn du diese Karte ausspielst, decke solange Karten von deinem Nachziehstapel auf, bis eine Geldkarte offen liegt. Lege die übrigen aufgedeckten Karten ab und spiele die Geldkarte aus. Wachturm - Ziehe solange Karten nach, bis du 6 Karten auf der Hand hast. Wenn du eine Karte nimmst oder kaufst darfst du den Wachturm aus deiner Hand aufdecken. Wenn du das machst: Entsorge die neue Karte oder lege sie sofort auf deinen Nachziehstapel. + Ziehe solange Karten nach, bis du 6 Karten auf der Hand hast.\nWenn du eine Karte nimmst oder kaufst darfst du den Wachturm aus deiner Hand aufdecken. Wenn du das machst: Entsorge die neue Karte oder lege sie sofort auf deinen Nachziehstapel. Arbeiterdorf Festplatz @@ -528,8 +528,8 @@ Wenn du diese Karte kaufst, nimm dir eine weitere Hafenstadt. Wildhüter Drehe deinen Reise-Marker um.\nLiegt die Vorderseite oben: +5 Karten - Ratcatcher - Put this on your Tavern mat. - At the start of your turn, you may call this, to trash a card from your hand. + Rattenfänger + Lege diese Karte auf dein Wirtshaustableau.\nZu Beginn deines Zuges darfst du diese Karte von deinem Tableau aufrufen. Wenn du das tust, musst du eine Handkarte entsorgen. Raze Trash this or a card from your hand. Look at a number of cards from the top of your deck equal to the cost in coins of the trashed card. Put one into your hand and discard the rest. Relikt @@ -558,9 +558,9 @@ Almosen Einmal pro Zug: Wenn du keine Geldkarten im Spiel hast, nimm dir eine Karte, die bis zu 4 Geld kostet. Ball - Take your -$1 token. Gain 2 cards each costing up to $4. - Bonfire - Trash up to 2 cards you have in play. + Nimm deinen -1 Geld-Marker. Nimm dir 2 Karten, die jede bis zu 4 Geld kostet. + Freudenfeuer + Entsorge bis zu 2 Karten, die du im Spiel hast. Leihgabe Einmal pro Zug: Wenn dein -1 Karte-Marker nicht auf deinem Nachziehstapel liegt, lege ihn dorthin und +1 Geld. Expedition @@ -575,8 +575,8 @@ Once per turn: If the previous turn wasn\'t yours, take another turn after this one, in which you can\'t buy cards. Pathfinding Move your +1 Card token to an Action Supply pile (when you play a card from that pile, you first get +1 Card). - Pilgrimage - Once per turn: Turn your Journey token over (it starts face up); then if it\'s face up, choose up to 3 differently named cards you have in play and gain a copy of each. + Pilgerfahrt + Einmal pro Zug: Drehe deinen Reise-Marker um. Liegt die Vorderseite oben: Wähle bis zu 3 Karten mit unterschiedlichem Namen, die du im Spiel hast und nimm dir jeweils eine davon. Plan Move your Trashing token to an Action Supply pile (when you buy a card from that pile, you may trash a card from your hand.) Quest @@ -589,12 +589,12 @@ Sieh dir die obersten 5 Karten deines Nachziehstapels an. Lege 3 davon ab und den Rest in beliebiger Reihenfolge zurück auf den Nachziehstapel. Seaway Gain an Action card costing up to $4. Move your +1 Buy token to its pile (when you play a card from that pile, you first get +1 Buy). - Trade - Trash up to 2 cards from your hand. Gain a Silver per card you trashed. + Handel + Entsorge bis zu 2 Handkarten. Nimm dir für jede entsorgte Karte ein Silber. Training Move your +$1 token to an Action Supply pile (when you play a card from that pile, you first get +$1). - TravellingFair - When you gain a card this turn, you may put it on top of your deck. + Wanderzirkus + Wenn du in diesem Zug eine Karte nimmst, darfst du sie auf deinen Nachziehstapel legen. Gesandter Decke die obersten 5 Karten von deinem Nachziehstapel auf. Der Spieler links von dir wählt eine der aufgedeckten Karten aus. Lege die gewählte Karte ab. Nimm die übrigen Karten auf die Hand. diff --git a/androminion/res/values-de/strings-server.xml b/androminion/res/values-de/strings-server.xml index 2a522608f..1d2cb1f3a 100644 --- a/androminion/res/values-de/strings-server.xml +++ b/androminion/res/values-de/strings-server.xml @@ -78,6 +78,7 @@ %1$s eine Karte, die du im Spiel hast %2$s bis zu %1$s Karten, die du im Spiel hast %2$s genau %1$s Karten, die du im Spiel hast + %2$s bis zu %1$s Karten mit unterschiedlichem Namen, die du im Spiel hast. Wähle Reaktionskarte zum Zeigen Zeige Bannkarte (%1$s) @@ -130,6 +131,7 @@ Karte beiseite gelegt (Prinz) Karte auf Insel-Tableau gelegt Nachziehstapel auf Ablagestapel gelegt + Reisender eingetauscht in Reise-Marker auf Vorderseite gedreht Reise-Marker auf Rückseite gedreht -1 Geld-Marker vor sich platziert @@ -373,7 +375,7 @@ Geisterwald im Spiel %1$s Sumpfhexe im Spiel %1$s Sumpfhexen im Spiel - Tausche aus gegen %1$s + Tausche ein gegen %1$s Vom Tableau ablegen Wähle Anzahl Weinhändler, die du vom Tableau ablegst diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index f8d91dd6f..ac604d364 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -90,6 +90,7 @@ Pick a card you have in play to %1$s Pick up to %1$s cards you have in play to %2$s Pick exactly %1$s cards you have in play to %2$s + Pick up to %1$s differently named cards you have in play to %2$s Select reaction card to reveal Reveal Bane card (%1$s) @@ -152,6 +153,7 @@ Card set aside (Gear) Card set aside on island mat Deck put into discard pile + Traveller exchanged for Journey token turned face up Journey token turned face down -1 coin token placed diff --git a/androminion/src/com/mehtank/androminion/ui/DeckView.java b/androminion/src/com/mehtank/androminion/ui/DeckView.java index 3407a1815..f454bd64b 100644 --- a/androminion/src/com/mehtank/androminion/ui/DeckView.java +++ b/androminion/src/com/mehtank/androminion/ui/DeckView.java @@ -86,7 +86,6 @@ public void set(String nameStr, int turns, int deckSize, int handSize, int numCa else journeyToken.setVisibility(INVISIBLE); - /*frr18 todo -1 Card*/ minusOneCardToken.setText(" -1 "); if (minusOneCardTokenOn) minusOneCardToken.setVisibility(VISIBLE); diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 05d59895e..ec37062fa 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -287,6 +287,8 @@ public static String getStatusText(Event event, Object[] extras) { statusText += getString(R.string.CardSetAsideOnIslandMat); } else if (event.gameEventType == GameEvent.Type.DeckPutIntoDiscardPile) { statusText += getString(R.string.DeckPutIntoDiscardPile); + } else if (event.gameEventType == GameEvent.Type.TravellerExchanged) { + statusText += getString(R.string.TravellerExchanged); } else if (event.gameEventType == GameEvent.Type.TurnJourneyTokenFaceUp) { statusText += getString(R.string.TurnJourneyTokenFaceUp); } else if (event.gameEventType == GameEvent.Type.TurnJourneyTokenFaceDown) { @@ -926,7 +928,7 @@ public static String[] getBooleanStrings(Card cardResponsible, Object[] extras) } else if (cardName.equals(getCardName(Cards.raze))) { strings[1] = getString(R.string.trash_this); strings[2] = getString(R.string.trash_card_from_hand); - } else if (cardName.equals(getCardName(Cards.royalSeal))) { + } else if (cardName.equals(getCardName(Cards.royalSeal)) || cardName.equals(getCardName(Cards.travellingFair))) { strings[0] = getCardRevealedHeader(extras); strings[1] = getString(R.string.top_of_deck); strings[2] = getString(R.string.take_normal); @@ -1106,8 +1108,12 @@ else if(sco.exactCount) str = Strings.format(R.string.select_one_card_from_played, header); else if(sco.exactCount) str = Strings.format(R.string.select_exactly_x_cards_from_played, "" + sco.count, header); - else - str = Strings.format(R.string.select_up_to_x_cards_from_played, "" + sco.count, header); + else { + if (sco.different) + str = Strings.format(R.string.select_up_to_x_different_cards_from_played, "" + sco.count, header); + else + str = Strings.format(R.string.select_up_to_x_cards_from_played, "" + sco.count, header); + } return str; } throw new RuntimeException("SelectCardOptions isn't from table or from hand or from played..."); @@ -1211,10 +1217,12 @@ private static void initActionStrings() { getCardName(Cards.ratcatcher), getCardName(Cards.raze), getCardName(Cards.storyteller), + getCardName(Cards.trade), getCardName(Cards.transmogrify), /*Adventures Events*/ getCardName(Cards.alms), getCardName(Cards.ball), + getCardName(Cards.pilgrimage), getCardName(Cards.seaway) )); diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index b210306d6..cb24a7e57 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -47,12 +47,13 @@ public enum Type { CalledCard, // A card was called from the tavern mat CardSetAsideOnIslandMat, // A card was set aside on island mat DeckPutIntoDiscardPile, // Deck put into discard pile + TravellerExchanged, // traveller exchanged TurnJourneyTokenFaceUp, // journey token turned face up TurnJourneyTokenFaceDown, // journey token turned face down - MinusOneCoinTokenOn, // -1 Coin token taken by player - MinusOneCoinTokenOff, // -1 Coin token removed by player - MinusOneCardTokenOn, // -1 Card token put on deck by player - MinusOneCardTokenOff, // -1 Card token drawn from deck by player + MinusOneCoinTokenOn, // -1 Coin token placed + MinusOneCoinTokenOff, // -1 Coin token removed + MinusOneCardTokenOn, // -1 Card token put onto deck + MinusOneCardTokenOff, // -1 Card token drawn from deck PlusOneCardTokenMoved, // +1 Card token moved to supply pile PlusOneActionTokenMoved, // +1 Action token moved to supply pile PlusOneBuyTokenMoved, // +1 Buy token moved to supply pile diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index f357c4741..bf70a7d0c 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -79,6 +79,7 @@ public enum PickType { public boolean isAttack = false; public boolean isNonShelter = false; public boolean isSupplyCard = false; + public boolean different = false; public int noTokensForPlayer = -1; public boolean passable = false; public String header = null; @@ -86,6 +87,7 @@ public enum PickType { //public SelectCardOptions setType(SelectType s) {selectType = s; return this;} public SelectCardOptions setHeader(String s) {header = s; return this;} + public SelectCardOptions setDifferent() {different = true; return this;} public SelectCardOptions setPassable() {passable = true; return this;} public SelectCardOptions setPickType(PickType pickType) {this.pickType = pickType;return this;} public SelectCardOptions setActionType(ActionType actionType) {this.actionType = actionType;return this;} @@ -151,9 +153,10 @@ public boolean checkValid(MyCard c) { return checkValid(c, 0, false); } + /* Note: This method must be synchrony with checkValid(Card c, int cost, boolean cardIsVictory) */ public boolean checkValid(MyCard c, int cost, boolean hasTokens) { - if ((maxCost >= 0) && (cost > maxCost )) return false; + if ((maxCost >= 0) && (cost > (c.costPotion ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; if (noTokensForPlayer != -1 && hasTokens) return false; @@ -180,6 +183,7 @@ public boolean checkValid(Card c, boolean cardIsVictory) { return checkValid(c, 0, cardIsVictory, false); } + /* Note: This method must be synchrony with checkValid(MyCard c, int cost) */ public boolean checkValid(Card c, int cost, boolean cardIsVictory, boolean hasTokens) { if ((maxCost >= 0) && (cost > (c.costPotion() ? maxCost : maxCostWithoutPotion))) return false; @@ -204,10 +208,14 @@ public boolean checkValid(Card c, int cost, boolean cardIsVictory, boolean hasTo } else { if (isAction || isAttack) return false; } - if ((isBuyPhase || isSupplyCard) && !Cards.isSupplyCard(c) && !c.isEvent()) return false; + if (isBuyPhase && !Cards.isSupplyCard(c) && !c.isEvent()) return false; + if (isSupplyCard && !Cards.isSupplyCard(c)) return false; return true; } + public boolean isDifferent() { + return different; + } public boolean isPassable() { return passable; } diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index bec820eef..fbfd9b467 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -149,6 +149,8 @@ protected int getCoinEstimate(MoveContext context) { } coin += bankcount * (treasurecards + venturecount) - (bankcount*bankcount + bankcount) / 2; coin += context.player.getGuildsCoinTokenCount(); + if(context.player.getMinusOneCoinToken() && coin > 0) + coin--; coin += context.getCoins(); //TODO: estimate coin to get from actions in hand @@ -1543,7 +1545,7 @@ public boolean loan_shouldTrashTreasure(MoveContext context, TreasureCard treasu } @Override - public boolean royalSeal_shouldPutCardOnDeck(MoveContext context, Card card) { + public boolean royalSealTravellingFair_shouldPutCardOnDeck(MoveContext context, Card responsible, Card card) { if(isOnlyVictory(card)) { return false; } @@ -2972,6 +2974,8 @@ public int numGuildsCoinTokensToSpend(MoveContext context, int coinTokenTotal, b return coinTokenTotal; int gold = context.getCoinAvailableForBuy(); + if(getMinusOneCoinToken()) + gold--; int coinTokenToSpend = 0; if(game.isValidBuy(context, Cards.colony, gold + coinTokenTotal)) { @@ -3572,6 +3576,34 @@ public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); } + @Override + public Card[] pilgrimage_cardsToGain(MoveContext context) { + HashSet cardsToMatch = new HashSet(); + for(int i = 0; i < 2; i++) { + for(Card card : (i==0 ? context.getPlayer().playedCards : context.getPlayer().nextTurnCards)) { + if(Cards.isSupplyCard(card) && context.getCardsLeftInPile(card) > 0) { + boolean good = true; + for(Card trash : getTrashCards()) { + if(card.equals(trash)) { + good = false; + break; + } + } + if(good) { + cardsToMatch.add(card); + } + } + } + } + ArrayList sorted = new ArrayList(); + sorted.addAll(cardsToMatch); + Collections.sort(sorted, Collections.reverseOrder(new Util.CardCostComparator())); + CardList s = new CardList(context.getPlayer(), context.getPlayer().getPlayerName()); + for(Card c : sorted) + s.add(c); + return pickOutCards(s, 3, s.toArray()); + } + @Override public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); @@ -3593,6 +3625,10 @@ public ActionCard seaway_cardToObtain(MoveContext context) { return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); } + public Card[] trade_cardsToTrash(MoveContext context) { + return pickOutCards(context.getPlayer().getHand(), 2, getTrashCards()); + } + @Override public ActionCard training_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 3bdb4dc96..00ae3f41c 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -1,6 +1,7 @@ package com.vdom.core; import java.util.ArrayList; +import java.util.HashSet; import com.vdom.api.ActionCard; import com.vdom.api.Card; @@ -79,6 +80,9 @@ public void isBuying(MoveContext context) { case Pathfinding: pathfinding(context); break; + case Pilgrimage: + pilgrimage(context); + break; case Plan: plan(context); break; @@ -94,9 +98,14 @@ public void isBuying(MoveContext context) { case Seaway: seaway(context); break; + case Trade: + trade(context); + break; case Training: training(context); break; + case TravellingFair: + context.travellingFairBought = true; default: break; } @@ -177,6 +186,32 @@ private void pathfinding(MoveContext context) { placeToken(context, card, PlayerSupplyToken.PlusOneCard); } + private void pilgrimage(MoveContext context) { + if(context.player.flipJourneyToken(context)) { + Card[] cards = context.player.controlPlayer.pilgrimage_cardsToGain(context); + if (cards != null) { + if (cards.length > 3) { + Util.playerError(context.player, "Pilgrimage gain error, trying to gain too many cards, ignoring."); + } else { + HashSet differentCards = new HashSet(); + for (Card card : cards) { + differentCards.add(card); + } + for (Card card : differentCards) { + if(context.player.playedCards.contains(card) || + context.player.nextTurnCards.contains(card) || + context.player.playedByPrince.contains(card)) { + context.player.gainNewCard(card, this.controlCard, context); + } else { + Util.playerError(context.player, "Pilgrimage gain error, card not in play, ignoring."); + } + } + } + } + } + context.cantBuy.add(this); //once per turn + } + private void plan(MoveContext context) { ActionCard card = context.getPlayer().controlPlayer.plan_actionCardPileToHaveToken(context); placeToken(context, card, PlayerSupplyToken.Trashing); @@ -298,4 +333,24 @@ private void training(MoveContext context) { placeToken(context, card, PlayerSupplyToken.PlusOneCoin); } + private void trade(MoveContext context) { + Card[] cards = context.player.controlPlayer.trade_cardsToTrash(context); + if (cards != null) { + if (cards.length > 2) { + Util.playerError(context.player, "Trade trash error, trying to trash too many cards, ignoring."); + } else { + for (Card card : cards) { + for (int i = 0; i < context.player.hand.size(); i++) { + Card inHand = context.player.hand.get(i); + if (inHand.equals(card)) { + context.player.trash(context.player.hand.remove(i, false), this.controlCard, context); + context.player.gainNewCard(Cards.silver, this, context); + break; + } + } + } + } + } + } + } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 47a69c3ff..494bbdba2 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -740,15 +740,17 @@ protected void playerBeginTurn(Player player, MoveContext context) { * now that you have more cards to choose from. */ for (int clone = ((CardImpl) card).cloneCount; clone > 0; clone--) { - durationCards.add((DurationCard) thisCard); if( thisCard.equals(Cards.amulet) || thisCard.equals(Cards.dungeon)) { allDurationAreSimple = false; } if(thisCard.equals(Cards.haven) || thisCard.equals(Cards.gear)) { - durationCards.add(player.haven.remove(0)); + if(player.haven != null && player.haven.size() > 0) { + durationCards.add((DurationCard) thisCard); + durationCards.add(player.haven.remove(0)); + } } else { - durationCards.add(Cards.curse); /*dummy*/ + durationCards.add((DurationCard) thisCard); } } } else if( thisCard.equals(Cards.throneRoom) @@ -2416,8 +2418,10 @@ public void gameEvent(GameEvent event) { } if(!handled) { - if (context.isRoyalSealInPlay() && context.player.controlPlayer.royalSeal_shouldPutCardOnDeck((MoveContext) context, event.card)) { + if (context.isRoyalSealInPlay() && context.player.controlPlayer.royalSealTravellingFair_shouldPutCardOnDeck((MoveContext) context, Cards.royalSeal, event.card)) { player.putOnTopOfDeck(event.card, context, true); + } else if (context.travellingFairBought && context.player.controlPlayer.royalSealTravellingFair_shouldPutCardOnDeck((MoveContext) context, Cards.travellingFair, event.card)) { + player.putOnTopOfDeck(event.card, context, true); } else if (event.card.equals(Cards.nomadCamp)) { player.putOnTopOfDeck(event.card, context, true); } else if (event.responsible != null) { diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 160109853..e15f94ecf 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -76,7 +76,13 @@ private Card[] getFromHandOrPlayed(boolean fromTheHand, MoveContext context, Sel if (fromTheHand) { sco = sco.fromHand(); } else { - localHand = context.player.playedCards; + localHand = new CardList(context.getPlayer(), context.getPlayer().getPlayerName()); + for (Card card : context.player.playedCards) { + localHand.add(card); + } + for (Card card : context.player.nextTurnCards) { + localHand.add(card); + } sco = sco.fromPlayed(); } @@ -1178,14 +1184,14 @@ public Card[] rabble_attack_cardOrder(MoveContext context, Card[] cards) { } @Override - public boolean royalSeal_shouldPutCardOnDeck(MoveContext context, Card card) { - if(context.isQuickPlay() && shouldAutoPlay_royalSeal_shouldPutCardOnDeck(context, card)) { - return super.royalSeal_shouldPutCardOnDeck(context, card); + public boolean royalSealTravellingFair_shouldPutCardOnDeck(MoveContext context, Card responsible, Card card) { + if(context.isQuickPlay() && shouldAutoPlay_royalSealTravellingFair_shouldPutCardOnDeck(context, responsible, card)) { + return super.royalSealTravellingFair_shouldPutCardOnDeck(context, responsible, card); } Object[] extras = new Object[2]; - extras[0] = Cards.royalSeal; + extras[0] = responsible; /* royalSeal or travellingFair */ extras[1] = card; - return selectBoolean(context, Cards.royalSeal, extras); + return selectBoolean(context, responsible, extras); } @Override @@ -2485,9 +2491,9 @@ public Card stonemason_cardToTrash(MoveContext context) { @Override public Card stonemason_cardToGain(MoveContext context, int maxCost, boolean potion) { - SelectCardOptions sco = new SelectCardOptions().allowEmpty().maxCost(maxCost) - .potionCost(potion ? 1 : 0).setActionType(ActionType.GAIN) - .setCardResponsible(Cards.stonemason); + SelectCardOptions sco = new SelectCardOptions().allowEmpty().potionCost(potion?1:0) + .maxCost(maxCost).maxCostWithoutPotion() + .setActionType(ActionType.GAIN).setCardResponsible(Cards.stonemason); return getFromTable(context, sco); } @@ -2840,6 +2846,17 @@ public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) getFromTable(context, sco); } + @Override + public Card[] pilgrimage_cardsToGain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_pilgrimage_cardsToGain(context)) { + return super.pilgrimage_cardsToGain(context); + } + SelectCardOptions sco = new SelectCardOptions().setCount(3).setDifferent() + .setPassable().setPickType(PickType.SELECT) + .setCardResponsible(Cards.pilgrimage).setActionType(ActionType.GAIN); + return getFromPlayed(context, sco); + } + @Override public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_plan_actionCardPileToHaveToken(context)) { @@ -2872,6 +2889,17 @@ public ActionCard seaway_cardToObtain(MoveContext context) { .setCardResponsible(Cards.seaway).isAction().setActionType(ActionType.GAIN); return (ActionCard) getFromTable(context, sco); } + + @Override + public Card[] trade_cardsToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_trade_cardsToTrash(context)) { + return super.trade_cardsToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setCount(2) + .setPassable().setPickType(PickType.TRASH) + .setCardResponsible(Cards.trade).setActionType(ActionType.TRASH); + return getFromHand(context, sco); + } @Override public ActionCard training_actionCardPileToHaveToken(MoveContext context) { diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index fcbe1aa03..d6a6083d1 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -41,6 +41,7 @@ public class MoveContext { public ArrayList cantBuy = new ArrayList(); public int beggarSilverIsOnTop = 0; public boolean graverobberGainedCardOnTop = false; + public boolean travellingFairBought = false; public enum PileSelection {DISCARD,HAND,DECK,ANY}; public PileSelection hermitTrashCardPile = PileSelection.ANY; diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 4b32e57b2..0b8e8c6df 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1002,8 +1002,15 @@ else if(!commandedDiscard && cleanup && card.isTraveller()) { // XXX making game slow; is this necessary? For that matter, are discarded cards public? if(context != null && (commandedDiscard || exchange != null)) { - GameEvent event = new GameEvent(GameEvent.Type.CardDiscarded, context); - event.card = (exchange != null ? exchange : card); + GameEvent event; + if(exchange != null) { + event = new GameEvent(GameEvent.Type.TravellerExchanged, context); + event.card = (exchange); + } else { + event = new GameEvent(GameEvent.Type.CardDiscarded, context); + event.card = (card); + } + event.responsible = responsible; event.setPlayer(this); context.game.broadcastEvent(event); @@ -1490,7 +1497,7 @@ public ArrayList getActionsInHand() { public abstract Card[] rabble_attack_cardOrder(MoveContext context, Card[] cards); - public abstract boolean royalSeal_shouldPutCardOnDeck(MoveContext context, Card card); + public abstract boolean royalSealTravellingFair_shouldPutCardOnDeck(MoveContext context, Card responsible, Card card); public abstract Card tradeRoute_cardToTrash(MoveContext context); @@ -1748,11 +1755,13 @@ public ArrayList getActionsInHand() { public abstract ActionCard ferry_actionCardPileToHaveToken(MoveContext context); public abstract ActionCard lostArts_actionCardPileToHaveToken(MoveContext context); public abstract ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context); + public abstract Card[] pilgrimage_cardsToGain(MoveContext context); public abstract ActionCard plan_actionCardPileToHaveToken(MoveContext context); public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); public abstract ActionCard seaway_cardToObtain(MoveContext context); public abstract ActionCard training_actionCardPileToHaveToken(MoveContext context); public abstract Card trashingToken_cardToTrash(MoveContext context); + public abstract Card[] trade_cardsToTrash(MoveContext context); // //////////////////////////////////////////// // Card interactions - Promotional Cards diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 2a2d2db33..4fd118021 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -469,7 +469,7 @@ public boolean shouldAutoPlay_loan_shouldTrashTreasure(MoveContext context, Card } - public boolean shouldAutoPlay_royalSeal_shouldPutCardOnDeck(MoveContext context, Card card) { + public boolean shouldAutoPlay_royalSealTravellingFair_shouldPutCardOnDeck(MoveContext context, Card responsible, Card card) { return true; } @@ -908,6 +908,10 @@ public boolean shouldAutoPlay_pathfinding_actionCardPileToHaveToken(MoveContext return false; } + public boolean shouldAutoPlay_pilgrimage_cardsToGain(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_plan_actionCardPileToHaveToken(MoveContext context) { return false; } @@ -920,6 +924,10 @@ public boolean shouldAutoPlay_seaway_cardToObtain(MoveContext context) { return false; } + public boolean shouldAutoPlay_trade_cardsToTrash(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_training_actionCardPileToHaveToken(MoveContext context) { return false; } diff --git a/vdom/src/com/vdom/core/UI.java b/vdom/src/com/vdom/core/UI.java index 5815c7261..c212c4c30 100644 --- a/vdom/src/com/vdom/core/UI.java +++ b/vdom/src/com/vdom/core/UI.java @@ -325,7 +325,7 @@ public void gameEvent(GameEvent event) { sleep(GAME_END_SLEEP); } - if ((event.getType() == GameEvent.Type.PlayingAction || event.getType() == GameEvent.Type.PlayingDurationAction) + if ((event.getType() == GameEvent.Type.PlayingAction || event.getType() == GameEvent.Type.PlayingDurationAction || event.getType() == GameEvent.Type.CallingCard) && event.getPlayer() == Game.players[Game.playersTurn]) { // System.out.println("playing action:" + event.getCard().getName()); showHand(Game.players[Game.playersTurn]); diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index f3c7da630..ba77eb08c 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -583,6 +583,9 @@ private int getCurrencyTotal(ArrayList list) { if (Util.getCardCount(list, Cards.foolsGold) > 1) { money += (Util.getCardCount(list, Cards.foolsGold) - 1) * 3; } + + if(getMinusOneCoinToken() && money > 0) + money--; return money; } From 88e1f76e333d556b6ab3731f61cc25f901a6dc8a Mon Sep 17 00:00:00 2001 From: dominionator Date: Tue, 5 Jan 2016 01:22:46 -0700 Subject: [PATCH 026/141] Implementing Mission Including option to resolve Mission effect before or after Outpost effect. Making Teacher card selection not require transmitting player index across RemotePlayer connection. --- androminion/res/values/strings-server.xml | 5 ++ .../com/mehtank/androminion/ui/GameTable.java | 15 +---- .../com/mehtank/androminion/ui/Strings.java | 11 ++++ .../src/com/vdom/comms/SelectCardOptions.java | 16 +++-- vdom/src/com/vdom/core/BasePlayer.java | 10 ++++ vdom/src/com/vdom/core/EventCardImpl.java | 8 +++ vdom/src/com/vdom/core/Game.java | 58 +++++++++++++++---- vdom/src/com/vdom/core/IndirectPlayer.java | 17 ++++-- vdom/src/com/vdom/core/MoveContext.java | 7 +++ vdom/src/com/vdom/core/Player.java | 17 +++--- vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 ++ vdom/src/com/vdom/players/VDomPlayerEarl.java | 3 + .../src/com/vdom/players/VDomPlayerSarah.java | 4 +- 13 files changed, 127 insertions(+), 48 deletions(-) diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index ac604d364..46e75a475 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -263,6 +263,11 @@ +(1) Coin + Choose extra turn order + Outpost first + Mission turn first + Possessed turn first + +2 Actions +2 Buys Gain a Silver diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 3f6516cd4..14177c301 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -67,7 +67,6 @@ public PlayerAdapter getPlayerAdapter() { LinearLayout turnView; View myCardView; private static int[] costs = {}; - private static int[][][] tokens = {}; TextView actionText; LinearLayout deckStatus; @@ -495,7 +494,7 @@ else if (sco.fromTable) { if (parent != prizePile) return false; } - return sco.checkValid(c, getCardCost(c), getHasTokensForPlayer(c, sco.noTokensForPlayer)); + return sco.checkValid(c, getCardCost(c)); } /** @@ -1074,7 +1073,6 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { this.lastEmbargos = gs.embargos; this.lastTokens = gs.tokens; costs = gs.costs; - tokens = gs.tokens; supplyPile.updateCardName(gs.ruinsID, gs.ruinsTopCard, -1, false); supplyPile.updateCardName(gs.knightsID, gs.knightsTopCard, gs.knightsTopCardCost, gs.knightsTopCardIsVictory); @@ -1089,17 +1087,6 @@ static int getCardCost(MyCard c) { return costs[c.id]; return c.cost; } - - static boolean getHasTokensForPlayer(MyCard c, int playerIndex) { - if (playerIndex == -1) - return false; - if (tokens == null || tokens.length == 0) - return false; - if (c.id >= tokens.length) return false; - int[][] cardTokens = tokens[c.id]; - if (playerIndex >= cardTokens.length) return false; - return tokens[c.id][playerIndex].length > 0; - } private void setCardCosts(View v) { if (v instanceof CardView) { diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index ec37062fa..114e57642 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -30,6 +30,7 @@ import com.vdom.core.Player.CountFirstOption; import com.vdom.core.Player.CountSecondOption; import com.vdom.core.Player.DoctorOverpayOption; +import com.vdom.core.Player.ExtraTurnOption; import com.vdom.core.Player.GovernorOption; import com.vdom.core.Player.GraverobberOption; import com.vdom.core.Player.HuntingGroundsOption; @@ -572,6 +573,8 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { return format(R.string.call_resolve_action_query, getCardName(card)); } else if (extras[0] instanceof String && ((String) extras[0]).equals(IndirectPlayer.OPTION_START_TURN_EFFECT)) { return getString(R.string.call_start_turn_query); + } else if (extras[0] instanceof ExtraTurnOption) { + return getString(R.string.extra_turns_query); } String cardName = getCardName(card); if (cardName.equals(getCardName(Cards.advisor))) { @@ -670,6 +673,14 @@ public static String getOptionText(Object option, Object[] extras) { } else if (option == AmuletOption.GainSilver) { return getString(R.string.gain_silver); } + } else if (option instanceof ExtraTurnOption) { + if (option == ExtraTurnOption.OutpostFirst) { + return getString(R.string.extra_turns_outpost_first); + } else if (option == ExtraTurnOption.MissionFirst) { + return getString(R.string.extra_turns_mission_first); + } else if (option == ExtraTurnOption.PossessionFirst) { + return getString(R.string.extra_turns_possession_first); + } } else if (option instanceof NoblesOption) { if (option == NoblesOption.AddCards) { return getString(R.string.nobles_option_one); diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index bf70a7d0c..ea1a1c4cc 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -80,7 +80,7 @@ public enum PickType { public boolean isNonShelter = false; public boolean isSupplyCard = false; public boolean different = false; - public int noTokensForPlayer = -1; + public boolean noTokens = false; public boolean passable = false; public String header = null; public ArrayList allowedCards = new ArrayList(); @@ -122,7 +122,7 @@ public enum PickType { public SelectCardOptions isNonVictory() {isNonVictory = true; return this;} public SelectCardOptions isAttack() {isAttack = true; return this;} public SelectCardOptions isSupplyCard() {isSupplyCard = true; return this;} - public SelectCardOptions noTokensForPlayer(int p) {noTokensForPlayer = p; return this;} + public SelectCardOptions noTokens() {noTokens = true; return this;} public SelectCardOptions allowedCards(int[] is) { for (int i : is) @@ -150,15 +150,14 @@ public void addValidCard(int card) { } public boolean checkValid(MyCard c) { - return checkValid(c, 0, false); + return checkValid(c, 0); } /* Note: This method must be synchrony with checkValid(Card c, int cost, boolean cardIsVictory) */ - public boolean checkValid(MyCard c, int cost, boolean hasTokens) { + public boolean checkValid(MyCard c, int cost) { if ((maxCost >= 0) && (cost > (c.costPotion ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; - if (noTokensForPlayer != -1 && hasTokens) return false; if (isAction && !c.isAction) return false; if (isReaction && !c.isReaction) return false; @@ -180,16 +179,15 @@ public boolean checkValid(MyCard c, int cost, boolean hasTokens) { } public boolean checkValid(Card c, boolean cardIsVictory) { - return checkValid(c, 0, cardIsVictory, false); + return checkValid(c, 0, cardIsVictory); } /* Note: This method must be synchrony with checkValid(MyCard c, int cost) */ - public boolean checkValid(Card c, int cost, boolean cardIsVictory, boolean hasTokens) { + public boolean checkValid(Card c, int cost, boolean cardIsVictory) { if ((maxCost >= 0) && (cost > (c.costPotion() ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; - if (noTokensForPlayer != -1 && hasTokens) return false; - + if (isReaction && !(Cards.isReaction(c))) return false; if (isTreasure && !(c instanceof TreasureCard)) return false; if (isNonTreasure && (c instanceof TreasureCard)) return false; diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index fbfd9b467..53c6ca41c 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -18,6 +18,7 @@ import com.vdom.api.GameEventListener; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; +import com.vdom.core.Player.ExtraTurnOption; public abstract class BasePlayer extends Player implements GameEventListener { //trash in this order! @@ -3570,6 +3571,15 @@ public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); } + + public ExtraTurnOption extraTurn_chooseOption(MoveContext context, ExtraTurnOption[] options) { + for (ExtraTurnOption option : options) { + if (option == ExtraTurnOption.OutpostFirst) { + return option; + } + } + return options[0]; //don't much about extra turn order as long as Outpost turn check happens first + } @Override public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 00ae3f41c..bb8fce09e 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -77,6 +77,9 @@ public void isBuying(MoveContext context) { case LostArts: lostArts(context); break; + case Mission: + mission(context); + break; case Pathfinding: pathfinding(context); break; @@ -181,6 +184,11 @@ private void lostArts(MoveContext context) { placeToken(context, card, PlayerSupplyToken.PlusOneAction); } + private void mission(MoveContext context) { + context.missionBought = true; + context.cantBuy.add(this); + } + private void pathfinding(MoveContext context) { ActionCard card = context.getPlayer().controlPlayer.pathfinding_actionCardPileToHaveToken(context); placeToken(context, card, PlayerSupplyToken.PlusOneCard); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 494bbdba2..dd74e7a17 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -9,8 +9,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; +import java.util.Queue; import java.util.Random; import com.vdom.api.ActionCard; @@ -26,6 +28,7 @@ import com.vdom.api.GameType; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; +import com.vdom.core.Player.ExtraTurnOption; import com.vdom.core.Player.WatchTowerOption; public class Game { @@ -207,6 +210,14 @@ public static void go(String[] args, boolean html) throws ExitException { FrameworkEvent frameworkEvent = new FrameworkEvent(FrameworkEvent.Type.AllDone); FrameworkEventHelper.broadcastEvent(frameworkEvent); } + + private static class ExtraTurnInfo { + public ExtraTurnInfo() {} + public ExtraTurnInfo(boolean canBuyCards) { + this.canBuyCards = canBuyCards; + } + public boolean canBuyCards = true; + } void start() throws ExitException { HashMap gameTypeSpecificWins = new HashMap(); @@ -244,10 +255,13 @@ void start() throws ExitException { playersTurn = 0; turnCount = 1; Util.debug("Turn " + turnCount); + + Queue extraTurnsInfo = new LinkedList(); while (!gameOver) { Player player = players[playersTurn]; - MoveContext context = new MoveContext(this, player); + boolean canBuyCards = extraTurnsInfo.isEmpty() ? true : extraTurnsInfo.remove().canBuyCards; + MoveContext context = new MoveContext(this, player, canBuyCards); playerBeginTurn(player, context); @@ -288,11 +302,11 @@ void start() throws ExitException { } } - boolean takeAnotherTurn = playerEndTurn(player, context); + extraTurnsInfo.addAll(playerEndTurn(player, context)); gameOver = checkGameOver(); if (!gameOver) { - setPlayersTurn(takeAnotherTurn); + setPlayersTurn(!extraTurnsInfo.isEmpty()); } } @@ -567,17 +581,17 @@ public int compare(Card o1, Card o2) { Util.debug("", true); } - protected boolean playerEndTurn(Player player, MoveContext context) { + protected List playerEndTurn(Player player, MoveContext context) { int handCount = 5; - boolean takeAnotherTurn = false; + List result = new ArrayList(); // Can only have at most two consecutive turns for (Card card : player.nextTurnCards) { Card behaveAsCard = card.behaveAsCard(); if ((behaveAsCard instanceof DurationCard) && ((DurationCard) behaveAsCard).takeAnotherTurn()) { handCount = ((DurationCard) behaveAsCard).takeAnotherTurnCardCount(); if (consecutiveTurnCounter <= 1) { - takeAnotherTurn = true; + result.add(new ExtraTurnInfo()); break; } } @@ -621,7 +635,28 @@ protected boolean playerEndTurn(Player player, MoveContext context) { } event = new GameEvent(GameEvent.Type.TurnEnd, context); broadcastEvent(event); - return takeAnotherTurn; + + if (context.missionBought && consecutiveTurnCounter <= 1) { + if (!result.isEmpty()) { + //ask player if they want to do mission turn with three cards or do outpost turn first then mission turn + // player not possessed because we are between turns + + //TODO: dominionator - integrate this with Possession turn logic + ExtraTurnOption[] options = new ExtraTurnOption[]{ExtraTurnOption.OutpostFirst, ExtraTurnOption.MissionFirst}; + switch(player.extraTurn_chooseOption(context, options)) { + case MissionFirst: + result.get(0).canBuyCards = false; + break; + case OutpostFirst: + result.add(new ExtraTurnInfo(false)); + break; + } + } else { + result.add(new ExtraTurnInfo(false)); + } + } + + return result; } protected void playerAction(Player player, MoveContext context) { @@ -751,12 +786,14 @@ protected void playerBeginTurn(Player player, MoveContext context) { } } else { durationCards.add((DurationCard) thisCard); + durationCards.add(Cards.curse); /*dummy*/ } } } else if( thisCard.equals(Cards.throneRoom) || thisCard.equals(Cards.disciple) || thisCard.equals(Cards.kingsCourt) || thisCard.equals(Cards.procession) + || thisCard.equals(Cards.royalCarriage) || thisCard.equals(Cards.bandOfMisfits)) { GameEvent event = new GameEvent(GameEvent.Type.PlayingDurationAction, context); event.card = thisCard; @@ -1294,6 +1331,9 @@ public boolean isValidBuy(MoveContext context, Card card, int gold) { if (thePile == null) { return false; } + if (!context.canBuyCards && !card.isEvent()) { + return false; + } if (context.blackMarketBuyPhase) { if (thePile.isBlackMarket() == false) { return false; @@ -1322,7 +1362,7 @@ else if (!card.isEvent()) { return false; } - if ((context.countCardsInPlay(Cards.copper) > 0) && card.equals(Cards.grandMarket)) { + if (card.equals(Cards.grandMarket) && (context.countCardsInPlay(Cards.copper) > 0)) { return false; } @@ -1709,7 +1749,6 @@ protected void initPlayers(int numPlayers, boolean isRandom) throws ExitExceptio String[] playerStartupInfo = playerClassesAndJars.get(i); if (playerStartupInfo[1] == null) { players[i] = (Player) Class.forName(playerStartupInfo[0]).newInstance(); - players[i].setPlayerIndex(i); } else { String key = playerStartupInfo[0] + "::" + playerStartupInfo[1]; // players[i] = cachedPlayers.get(key); @@ -1729,7 +1768,6 @@ protected void initPlayers(int numPlayers, boolean isRandom) throws ExitExceptio } players[i] = (Player) playerClass.newInstance(); - players[i].setPlayerIndex(i); } if(playerStartupInfo[2] != null) { players[i].setName(playerStartupInfo[2]); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index e15f94ecf..bfd9c4572 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -99,7 +99,7 @@ private Card[] getFromHandOrPlayed(boolean fromTheHand, MoveContext context, Sel ArrayList handList = new ArrayList(); for (Card card : localHand) { - if (sco.checkValid(card, card.getCost(context), card.isVictory(context), false)) { + if (sco.checkValid(card, card.getCost(context), card.isVictory(context))) { handList.add(card); sco.addValidCard(cardToInt(card)); } @@ -153,8 +153,9 @@ private Card getFromTable(MoveContext context, SelectCardOptions sco) { boolean hasTokens = context.game.getPlayerSupplyTokens(card, context.getPlayer()).size() > 0; if ( !(card.isEvent() && sco.cardResponsible != null && sco.cardResponsible.equals(Cards.contraband) ) && (sco.allowEmpty || !context.game.isPileEmpty(card))) { - if ( sco.checkValid(card, card.getCost(context), card.isVictory(context), hasTokens) - && ( !context.cantBuy.contains(card) + if ( sco.checkValid(card, card.getCost(context), card.isVictory(context)) + && (!(sco.noTokens && hasTokens)) + && ( (!context.cantBuy.contains(card) && (context.canBuyCards || card.isEvent())) || !sco.pickType.equals(PickType.BUY)) && !( !Cards.isSupplyCard(card) && sco.actionType != null @@ -2742,7 +2743,7 @@ public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, return super.teacher_actionCardPileToHaveToken(context, token); } SelectCardOptions sco = new SelectCardOptions() - .isAction().noTokensForPlayer(context.getPlayer().getPlayerIndex()).setCardResponsible(Cards.teacher); + .isAction().noTokens().setCardResponsible(Cards.teacher); //TODO: specify can only select piles without a token return (ActionCard) getFromTable(context, sco); } @@ -2921,5 +2922,13 @@ public Card trashingToken_cardToTrash(MoveContext context) { .setCardResponsible(Cards.plan); return getCardFromHand(context, sco); } + + @Override + public ExtraTurnOption extraTurn_chooseOption(MoveContext context, ExtraTurnOption[] options) { + if(context.isQuickPlay() && shouldAutoPlay_extraTurn_chooseOption(context, options)) { + return super.extraTurn_chooseOption(context, options); + } + return options[selectOption(context, null, options)]; + } } diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index d6a6083d1..822b88cb8 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -36,12 +36,14 @@ public class MoveContext { public int totalCardsBoughtThisTurn = 0; public int totalEventsBoughtThisTurn = 0; public int totalExpeditionBoughtThisTurn = 0; + public boolean canBuyCards = true; public boolean buyPhase = false; public boolean blackMarketBuyPhase = false; // this is not a really buyPhase (peddler costs 8, you can't spend Guilds coin tokens) public ArrayList cantBuy = new ArrayList(); public int beggarSilverIsOnTop = 0; public boolean graverobberGainedCardOnTop = false; public boolean travellingFairBought = false; + public boolean missionBought = false; public enum PileSelection {DISCARD,HAND,DECK,ANY}; public PileSelection hermitTrashCardPile = PileSelection.ANY; @@ -59,8 +61,13 @@ public enum PileSelection {DISCARD,HAND,DECK,ANY}; public Player attackedPlayer; public MoveContext(Game game, Player player) { + this(game, player, true); + } + + public MoveContext(Game game, Player player, boolean canBuyCards) { this.game = game; this.player = player; + this.canBuyCards = canBuyCards; // this.playedCards = player.playedCards; } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 0b8e8c6df..83f60a780 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -27,7 +27,6 @@ public abstract class Player { // Only used by InteractivePlayer currently private String name; - private int playerIndex; public int playerNumber; public int shuffleCount = 0; protected int turnCount = 0; @@ -86,14 +85,6 @@ public boolean isAi() { public void setName(String name) { this.name = name.replace("_", " "); } - - public void setPlayerIndex(int value) { - playerIndex = value; - } - - public int getPlayerIndex() { - return playerIndex; - } public int getCurrencyTotal(MoveContext context) { int coin = 0; @@ -1266,6 +1257,12 @@ public static enum AmuletOption { TrashCard, GainSilver } + + public static enum ExtraTurnOption { + OutpostFirst, + MissionFirst, + PossessionFirst + } // Context is passed for the player to add a GameEventListener // if they want or to see what cards the game has, etc. @@ -1762,6 +1759,8 @@ public ArrayList getActionsInHand() { public abstract ActionCard training_actionCardPileToHaveToken(MoveContext context); public abstract Card trashingToken_cardToTrash(MoveContext context); public abstract Card[] trade_cardsToTrash(MoveContext context); + + public abstract ExtraTurnOption extraTurn_chooseOption(MoveContext context, ExtraTurnOption[] options); // //////////////////////////////////////////// // Card interactions - Promotional Cards diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 4fd118021..c0d0e1352 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -936,4 +936,8 @@ public boolean shouldAutoPlay_trashingToken_cardToTrash(MoveContext context) { return true; } + public boolean shouldAutoPlay_extraTurn_chooseOption(MoveContext context, ExtraTurnOption[] options) { + return true; + } + } diff --git a/vdom/src/com/vdom/players/VDomPlayerEarl.java b/vdom/src/com/vdom/players/VDomPlayerEarl.java index a4aaab15c..951c15d44 100644 --- a/vdom/src/com/vdom/players/VDomPlayerEarl.java +++ b/vdom/src/com/vdom/players/VDomPlayerEarl.java @@ -661,6 +661,9 @@ else if (context.getBuysLeft() == 0) { card = null; } } + + if (!context.canBuy(card)) + card = null; return card; } diff --git a/vdom/src/com/vdom/players/VDomPlayerSarah.java b/vdom/src/com/vdom/players/VDomPlayerSarah.java index 433db332c..da0788e70 100644 --- a/vdom/src/com/vdom/players/VDomPlayerSarah.java +++ b/vdom/src/com/vdom/players/VDomPlayerSarah.java @@ -588,13 +588,13 @@ public Card doBuy(MoveContext context) { final double silverLine = .5d; if (favorSilverGoldPlat) { - if (game.pileSize(Cards.silver) > 0 && coinAvailableForBuy >= 3 && coinAvailableForBuy <= silverMax && rand.nextFloat() > silverLine) { + if (context.canBuy(Cards.silver) && game.pileSize(Cards.silver) > 0 && coinAvailableForBuy >= 3 && coinAvailableForBuy <= silverMax && rand.nextFloat() > silverLine) { if(context.getEmbargosIfCursesLeft(Cards.silver) == 0) { return Cards.silver; } } - if (game.pileSize(Cards.gold) > 0 && coinAvailableForBuy >= 6 && coinAvailableForBuy <= 6 && rand.nextFloat() > silverLine) { + if (context.canBuy(Cards.gold) && game.pileSize(Cards.gold) > 0 && coinAvailableForBuy >= 6 && coinAvailableForBuy <= 6 && rand.nextFloat() > silverLine) { if(context.getEmbargosIfCursesLeft(Cards.gold) == 0) { return Cards.gold; } From b07d156ca63831a416164869e92af36b850a8179 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 6 Jan 2016 00:55:36 -0700 Subject: [PATCH 027/141] Relic Changed order of Relic attack event message to be after reactions are resolved. Changed color of text to dark red instead of light red in UI for Treasure and Duration attacks. --- androminion/res/values/card_styles.xml | 8 ++++---- androminion/res/values/colors.xml | 1 + androminion/res/values/strings-cards.xml | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 3 +-- vdom/src/com/vdom/core/TreasureCardImpl.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/androminion/res/values/card_styles.xml b/androminion/res/values/card_styles.xml index dce7e18b6..a0068238e 100644 --- a/androminion/res/values/card_styles.xml +++ b/androminion/res/values/card_styles.xml @@ -40,8 +40,8 @@ - + @@ -27,7 +27,7 @@ @color/cardVictory @color/cardInverseTextColor - + @@ -107,9 +107,22 @@ @color/cardDefaultTextColor @color/cardDefaultTextBackgroundColor + + + + + + + + - + \ No newline at end of file diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index b0e12f03f..469091f9d 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -423,43 +423,15 @@ private View getViewForToken(int player, int tokenId) { token.setText(text); return token; } - - public int getPlayerColor(int playerNumber) { - switch(playerNumber) { - case 0: - return getResources().getColor(R.color.player1Color); - case 1: - return getResources().getColor(R.color.player2Color); - case 2: - return getResources().getColor(R.color.player3Color); - case 3: - return getResources().getColor(R.color.player4Color); - case 4: - return getResources().getColor(R.color.player5Color); - case 5: - default: - return getResources().getColor(R.color.player6Color); - } - } - private int getPlayerStrokeColor(int playerNumber) { - switch(playerNumber) { - case 0: - return getResources().getColor(R.color.player1LineColor); - case 1: - return getResources().getColor(R.color.player2LineColor); - case 2: - return getResources().getColor(R.color.player3LineColor); - case 3: - return getResources().getColor(R.color.player4LineColor); - case 4: - return getResources().getColor(R.color.player5LineColor); - case 5: - default: - return getResources().getColor(R.color.player6LineColor); + private int getPlayerColor(int playerIndex) { + return GameTable.getPlayerColor(getResources(), playerIndex); } + + private int getPlayerStrokeColor(int playerIndex) { + return GameTable.getPlayerStrokeColor(getResources(), playerIndex); } - + public void setCost(int newCost, boolean overpay) { cost.setText(" " + newCost + (overpay ? "+" : "") + " "); } diff --git a/androminion/src/com/mehtank/androminion/ui/DeckView.java b/androminion/src/com/mehtank/androminion/ui/DeckView.java index f454bd64b..4bc3e50d0 100644 --- a/androminion/src/com/mehtank/androminion/ui/DeckView.java +++ b/androminion/src/com/mehtank/androminion/ui/DeckView.java @@ -1,6 +1,7 @@ package com.mehtank.androminion.ui; import android.content.Context; +import android.graphics.Color; import android.graphics.Typeface; import android.preference.PreferenceManager; import android.util.AttributeSet; @@ -48,7 +49,10 @@ public DeckView(Context context, AttributeSet attrs) { } } - public void set(String nameStr, int turns, int deckSize, int handSize, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight) { + public void set(String nameStr, int turns, int deckSize, int handSize, int numCards, + int pt, int vt, int gct, + boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, + boolean highlight, boolean showColor, int color) { String txt = nameStr + getContext().getString(R.string.turn_header) + turns; name.setText(txt); if (highlight) { @@ -60,6 +64,11 @@ public void set(String nameStr, int turns, int deckSize, int handSize, int numCa // name.setBackgroundColor(Color.TRANSPARENT); name.setTypeface(Typeface.DEFAULT); } + if (showColor) { + name.setBackgroundColor(color); + } else { + name.setBackgroundColor(Color.TRANSPARENT); + } pirates.setText(" " + pt + " "); if (pt != 0) diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index e500af582..c81452737 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -3,7 +3,9 @@ import java.util.ArrayList; import android.content.Context; +import android.content.res.Resources; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -1011,7 +1013,9 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { turnStatus.setStatus(gs.turnStatus, gs.potions, myTurn); for (int i=0; i 0) + return true; + } + return false; + } + + static int getCardCost(MyCard c) { if (c == null) return 0; if (costs != null && c.id < costs.length) @@ -1239,4 +1251,68 @@ public boolean onItemLongClick(AdapterView parent, View view, int position, l CardView clickedCard = (CardView) view; return clickedCard.onLongClick(clickedCard); } + + public static int getPlayerColor(Resources resources, int playerIndex) { + switch(playerIndex) { + case 0: + return resources.getColor(R.color.player1Color); + case 1: + return resources.getColor(R.color.player2Color); + case 2: + return resources.getColor(R.color.player3Color); + case 3: + return resources.getColor(R.color.player4Color); + case 4: + return resources.getColor(R.color.player5Color); + case 5: + default: + return resources.getColor(R.color.player6Color); + } + } + + public static int getPlayerStrokeColor(Resources resources, int playerIndex) { + switch(playerIndex) { + case 0: + return resources.getColor(R.color.player1LineColor); + case 1: + return resources.getColor(R.color.player2LineColor); + case 2: + return resources.getColor(R.color.player3LineColor); + case 3: + return resources.getColor(R.color.player4LineColor); + case 4: + return resources.getColor(R.color.player5LineColor); + case 5: + default: + return resources.getColor(R.color.player6LineColor); + } + } + + public static int getPlayerTextBackgroundColor(Context context, int playerIndex) { + int attrId; + switch(playerIndex) { + case 0: + attrId = R.attr.player1TextBackgroundColor; + break; + case 1: + attrId = R.attr.player2TextBackgroundColor; + break; + case 2: + attrId = R.attr.player3TextBackgroundColor; + break; + case 3: + attrId = R.attr.player4TextBackgroundColor; + break; + case 4: + attrId = R.attr.player5TextBackgroundColor; + break; + case 5: + default: + attrId = R.attr.player6TextBackgroundColor; + } + TypedValue typedValue = new TypedValue(); + context.getTheme().resolveAttribute(attrId, typedValue, true); + int color = typedValue.data; + return color; + } } diff --git a/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java b/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java index d60681b52..01568c85d 100644 --- a/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java +++ b/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java @@ -50,7 +50,7 @@ public View getView(int pos, View origView, ViewGroup parent) { dv = (DeckView) origView; } ps = getItem(pos); - dv.set(ps.name, ps.turns, ps.deckSize, ps.handSize, ps.numCards, ps.pt, ps.vt, ps.gct, ps.minusOneCoinTokenOn, ps.minusOneCardTokenOn, ps.journeyTokenFaceUp, ps.highlight); + dv.set(ps.name, ps.turns, ps.deckSize, ps.handSize, ps.numCards, ps.pt, ps.vt, ps.gct, ps.minusOneCoinTokenOn, ps.minusOneCardTokenOn, ps.journeyTokenFaceUp, ps.highlight, ps.showColor, ps.color); return dv; } diff --git a/androminion/src/com/mehtank/androminion/util/PlayerSummary.java b/androminion/src/com/mehtank/androminion/util/PlayerSummary.java index 36ad40751..c1560872a 100644 --- a/androminion/src/com/mehtank/androminion/util/PlayerSummary.java +++ b/androminion/src/com/mehtank/androminion/util/PlayerSummary.java @@ -22,13 +22,15 @@ public class PlayerSummary { public boolean minusOneCoinTokenOn; public boolean minusOneCardTokenOn; public boolean highlight = false; + public boolean showColor = false; + public int color; public int turns; public PlayerSummary(String name) { this.name = name; } - public void set(String name, int turns, int deckSize, int handSize, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight){ + public void set(String name, int turns, int deckSize, int handSize, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight, boolean showColor, int color){ this.name = name; this.turns = turns; this.deckSize = deckSize; @@ -41,6 +43,8 @@ public void set(String name, int turns, int deckSize, int handSize, int numCards this.minusOneCoinTokenOn = minusOneCoinTokenOn; this.minusOneCardTokenOn = minusOneCardTokenOn; this.highlight = highlight; + this.showColor = showColor; + this.color = color; } @Override From 1c46ac10d90ad2ce254cebb47b6296d930e26c31 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 16 Jan 2016 16:46:51 -0700 Subject: [PATCH 038/141] Finishing token UI. Tokens now display with correct padding. Token display handles large numbers of tokens on card piles. Current tokens appear on card description on long-press. --- androminion/res/layout/view_card.xml | 4 +- androminion/res/layout/view_card_classic.xml | 8 + .../res/layout/view_card_descriptive.xml | 9 + androminion/res/values/strings-ui.xml | 13 +- .../com/mehtank/androminion/ui/CardView.java | 206 ++++++++++++++---- .../com/mehtank/androminion/ui/GameTable.java | 2 + .../mehtank/androminion/util/CardGroup.java | 8 +- 7 files changed, 208 insertions(+), 42 deletions(-) diff --git a/androminion/res/layout/view_card.xml b/androminion/res/layout/view_card.xml index 14f91eec7..6a141cdd2 100644 --- a/androminion/res/layout/view_card.xml +++ b/androminion/res/layout/view_card.xml @@ -47,14 +47,14 @@ android:background="@drawable/embargos" android:textColor="@android:color/white" android:visibility="gone" /> - + + + + + Bl. Market: %1$s card art Downloading card art from %1$s - + A + B + - Tokens - + +1 Card + +1 Action + +1 Buy + +1 Coin + -2 cost + Trashing + :\u0020 + ,\u0020 + Embargoes diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index 469091f9d..6a6f0df81 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -1,6 +1,7 @@ package com.mehtank.androminion.ui; import java.io.File; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; @@ -15,7 +16,6 @@ import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.graphics.Color; -import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; @@ -39,6 +39,7 @@ import com.mehtank.androminion.util.CheckableEx; import com.mehtank.androminion.util.HapticFeedback; import com.mehtank.androminion.util.HapticFeedback.AlertType; +import com.mehtank.androminion.util.PlayerAdapter; import com.vdom.comms.MyCard; import com.vdom.core.PlayerSupplyToken; @@ -52,14 +53,19 @@ public class CardView extends FrameLayout implements OnLongClickListener, Checka private TextView name; private View cardBox; private TextView cost, countLeft, embargos; + private int numEmbargos; private LinearLayout tokens; private TextView checked; private TextView cardDesc; + private PlayerAdapter players; private String viewstyle; private boolean autodownload; private Context top; private boolean hideCountLeft; + + private int[][] currentTokens; + private static final int MAX_TOKENS_ON_CARD = 4; CardGroup parent; private CardState state; @@ -207,6 +213,7 @@ else if (c.isShelter) int textColor = cardStyle.getColor(2, R.color.cardDefaultTextColor); int nameBgColor = cardStyle.getColor(1, R.color.cardDefaultTextBackgroundColor); int countColor = cardStyle.getColor(3, R.color.cardDefaultTextColor); + cardStyle.recycle(); cardBox.setBackgroundColor(bgColor); name.setTextColor(textColor); @@ -363,6 +370,7 @@ public void shade(boolean on) { } public void setEmbargos(int s) { + numEmbargos = s; if (s != 0) { embargos.setText(" " + s + " "); embargos.setVisibility(VISIBLE); @@ -371,56 +379,102 @@ public void setEmbargos(int s) { } } - public void setTokens(int[][] newTokens) { + public void setTokens(int[][] newTokens, PlayerAdapter players) { + this.players = players; + if (Arrays.deepEquals(newTokens, currentTokens)) { + return; + } + currentTokens = newTokens; tokens.removeAllViews(); + int numTokens = countTokens(newTokens); + if (numTokens > MAX_TOKENS_ON_CARD) { + if (countPlayersWithTokens(newTokens) > MAX_TOKENS_ON_CARD) { + tokens.addView(getViewForToken(-1, -1, numTokens)); + return; + } + for (int i = 0; i < newTokens.length; ++i) { + int numPlayerTokens = newTokens[i].length; + if (numPlayerTokens == 0) + continue; + tokens.addView(getViewForToken(i, -1, numPlayerTokens)); + } + return; + } + for (int i = 0; i < newTokens.length; ++i) { - int[] players = newTokens[i]; - for (int tokenId : players) { - View tokenView = getViewForToken(i, tokenId); + int[] playerTokens = newTokens[i]; + for (int tokenId : playerTokens) { + View tokenView = getViewForToken(i, tokenId, -1); if (tokenView != null) tokens.addView(tokenView); } } } - private View getViewForToken(int player, int tokenId) { + private int countPlayersWithTokens(int[][] tokensPerPlayer) { + int result = 0; + for (int[] tokens : tokensPerPlayer) { + if (tokens.length > 0) + result++; + } + return result; + } + + private int countTokens(int[][] tokensPerPlayer) { + int result = 0; + for (int[] tokens : tokensPerPlayer) { + result += tokens.length; + } + return result; + } + + @SuppressWarnings("deprecation") + private View getViewForToken(int player, int tokenId, int multiplier) { int backgroundId = R.drawable.circulartoken;; String text; - switch(PlayerSupplyToken.getById(tokenId)) { - case PlusOneCard: - backgroundId = R.drawable.rectangulartoken; - text = "+1"; - break; - case PlusOneAction: - text = "+A"; - break; - case PlusOneBuy: - text = "+B"; - break; - case PlusOneCoin: - text = "+1"; - break; - case MinusTwoCost: - text = "-2"; - break; - case Trashing: - text = "X"; - break; - default: - return null; + PlayerSupplyToken tokenType = PlayerSupplyToken.getById(tokenId); + if (tokenType != null) { + switch(tokenType) { + case PlusOneCard: + backgroundId = R.drawable.rectangulartoken; + text = "+1"; + break; + case PlusOneAction: + text = "+" + getContext().getString(R.string.token_plus_one_action_initial); + break; + case PlusOneBuy: + text = "+" + getContext().getString(R.string.token_plus_one_buy_initial); + break; + case PlusOneCoin: + text = "+1"; + break; + case MinusTwoCost: + text = "-2"; + break; + case Trashing: + text = "X"; + break; + default: + return null; + } + } else { + text = "x" + multiplier; } - float sd = getResources().getDisplayMetrics().scaledDensity; + float dp = getResources().getDisplayMetrics().density; - GradientDrawable background = (GradientDrawable)getResources().getDrawable(backgroundId).mutate(); - background.setColor(getPlayerColor(player)); - background.setStroke((int)(2 * dp), getPlayerStrokeColor(player)); TextView token = new TextView(getContext()); - token.setBackgroundDrawable(background); - int pad = (int)dp; - token.setTextSize(sd * 8); + if (player >= 0) { + GradientDrawable background = (GradientDrawable)getResources().getDrawable(backgroundId).mutate(); + background.setColor(getPlayerColor(player)); + background.setStroke((int)Math.ceil(2 * dp), getPlayerStrokeColor(player)); + token.setBackgroundDrawable(background); + } + int pad = (int) Math.ceil(dp); + int padSides = (int) Math.ceil(dp * 2); + token.setTextAppearance(getContext(), R.style.style_cardview_count); token.setTextColor(Color.BLACK); - token.setPadding(pad, pad, pad, pad); token.setText(text); + token.setPadding(padSides, pad, padSides, pad); return token; } @@ -525,7 +579,22 @@ public boolean onLongClick(View view) { ImageView im = new ImageView(view.getContext()); im.setImageURI(u); im.setScaleType(ImageView.ScaleType.FIT_CENTER); - v = im; + + String tokenDesc = getTokenDescription(); + if (!tokenDesc.isEmpty()) { + LinearLayout ll = new LinearLayout(view.getContext()); + ll.setOrientation(LinearLayout.VERTICAL); + ll.addView(im); + TextView textView = new TextView(view.getContext()); + textView.setPadding(15, 0, 15, 5); + textView.setText(tokenDesc); + ll.addView(textView); + v = ll; + } else { + v = im; + } + + } else { TextView textView = new TextView(view.getContext()); textView.setPadding(15, 0, 15, 5); @@ -539,6 +608,11 @@ public boolean onLongClick(View view) { text += "\n"; text += cardView.getCard().desc; + String tokenDescription = getTokenDescription(); + if (!tokenDescription.isEmpty()) { + text += "\n\n" + tokenDescription; + } + textView.setText( text ); v = textView; } @@ -559,6 +633,64 @@ public boolean onLongClick(View view) { return true; } + private String getTokenDescription() { + String text = ""; + boolean hasPlayerTokens = players != null && currentTokens != null && countTokens(currentTokens) > 0; + if (hasPlayerTokens || numEmbargos > 0) { + text += getContext().getString(R.string.token_header); + text += "\n"; + if (numEmbargos > 0) { + text += getContext().getString(R.string.token_embargo) + getContext().getString(R.string.token_colon) + numEmbargos; + text += "\n"; + } + if (hasPlayerTokens) { + for (int i = 0; i < currentTokens.length; ++i) { + int[] playerTokens = currentTokens[i]; + if (playerTokens.length == 0) + continue; + text += players.getItem(i).name + getContext().getString(R.string.token_colon); + String separator = ""; + boolean first = true; + for (int tokenId : playerTokens) { + PlayerSupplyToken tokenType = PlayerSupplyToken.getById(tokenId); + int tokenNameId; + if (tokenType != null) { + switch(tokenType) { + case PlusOneCard: + tokenNameId = R.string.token_plus_one_card; + break; + case PlusOneAction: + tokenNameId = R.string.token_plus_one_action; + break; + case PlusOneBuy: + tokenNameId = R.string.token_plus_one_buy; + break; + case PlusOneCoin: + tokenNameId = R.string.token_plus_one_coin; + break; + case MinusTwoCost: + tokenNameId = R.string.token_minus_2_cost; + break; + case Trashing: + tokenNameId = R.string.token_trashing; + break; + default: + continue; + } + text += separator + getContext().getString(tokenNameId); + if (first) { + first = false; + separator = getContext().getString(R.string.token_separator); + } + } + } + text += "\n"; + } + } + } + return text; + } + public String GetCardTypeString(MyCard c) { String cardType = ""; diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index c81452737..e59531bf9 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -338,6 +338,8 @@ public void newGame(MyCard[] cards, String[] players) { addCardToTable(c); for (String s : players) addPlayer(s); + vpPile.setPlayers(getPlayerAdapter()); + supplyPile.setPlayers(getPlayerAdapter()); boolean platInPlay = false; for (MyCard c : cards) diff --git a/androminion/src/com/mehtank/androminion/util/CardGroup.java b/androminion/src/com/mehtank/androminion/util/CardGroup.java index 8da3192ab..894034335 100644 --- a/androminion/src/com/mehtank/androminion/util/CardGroup.java +++ b/androminion/src/com/mehtank/androminion/util/CardGroup.java @@ -14,7 +14,6 @@ import com.mehtank.androminion.ui.Strings; import com.vdom.api.Card; import com.vdom.comms.MyCard; -import com.vdom.comms.MyCard.CardNonSupplyComparator; /** * Collection of cards (e.g. hand, row of piles) that is displayed in a row / table @@ -28,6 +27,7 @@ public class CardGroup extends BaseAdapter { private ArrayList cards = new ArrayList(); private Comparator cmp = new MyCard.CardCostNameComparator(); private boolean sorted = false; + private PlayerAdapter players; // fix bug that lets item countLeft jump around int[] supplySizes = null; @@ -69,6 +69,10 @@ public void addCard(MyCard c, boolean state) { cards.add(ci); notifyDataSetChanged(); } + + public void setPlayers(PlayerAdapter players) { + this.players = players; + } public void updateState(int pos, CardState cs){ cards.set(pos, cs); @@ -116,7 +120,7 @@ public View getView(int pos, View origView, ViewGroup parent) { if (embargos != null) cv.setEmbargos(embargos[cs.c.id]); if (tokens != null) - cv.setTokens(tokens[cs.c.id]); + cv.setTokens(tokens[cs.c.id], players); } catch (ArrayIndexOutOfBoundsException e) { // TODO See why this is happening? Log.w(TAG, "exception", e); From 78c3b278321ba4a58c08dba0e06e225425b1832e Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 18 Jan 2016 12:33:09 -0700 Subject: [PATCH 039/141] WIP: Stash Promo Card. Stash card has red outline to represent red border. When Stash is on top of any player's deck, deck indicator turns red. When Stash cards are in any player's hand, red indicator number appears next to number of cards in hand. Still missing correct number of cards still to draw. --- androminion/res/drawable/stashborder.xml | 17 +++ androminion/res/drawable/thinstashborder.xml | 22 ++++ androminion/res/layout/view_deck.xml | 36 ++++++- androminion/res/values-de/strings-cards.xml | 2 + androminion/res/values-es/strings-cards.xml | 2 + androminion/res/values-fr/strings-cards.xml | 2 - androminion/res/values-ja/strings-cards.xml | 3 + androminion/res/values-nl/strings-cards.xml | 2 + androminion/res/values/attrs.xml | 1 + androminion/res/values/colors.xml | 3 + androminion/res/values/strings-cards.xml | 2 + androminion/res/values/strings-server.xml | 10 ++ androminion/res/values/styles.xml | 5 + .../com/mehtank/androminion/ui/CardView.java | 13 +-- .../com/mehtank/androminion/ui/DeckView.java | 38 +++++-- .../com/mehtank/androminion/ui/GameTable.java | 2 +- .../com/mehtank/androminion/ui/Strings.java | 49 +++++++++ .../androminion/util/PlayerAdapter.java | 2 +- .../androminion/util/PlayerSummary.java | 6 +- vdom/src/com/vdom/comms/GameStatus.java | 6 +- vdom/src/com/vdom/comms/MyCard.java | 1 + vdom/src/com/vdom/core/BasePlayer.java | 8 +- vdom/src/com/vdom/core/Cards.java | 4 +- vdom/src/com/vdom/core/Game.java | 13 +-- vdom/src/com/vdom/core/IndirectPlayer.java | 53 ++++++++++ vdom/src/com/vdom/core/Player.java | 100 +++++++++++++++--- vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 + vdom/src/com/vdom/core/RemotePlayer.java | 9 ++ 28 files changed, 369 insertions(+), 46 deletions(-) create mode 100644 androminion/res/drawable/stashborder.xml create mode 100644 androminion/res/drawable/thinstashborder.xml diff --git a/androminion/res/drawable/stashborder.xml b/androminion/res/drawable/stashborder.xml new file mode 100644 index 000000000..e25214ed0 --- /dev/null +++ b/androminion/res/drawable/stashborder.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/androminion/res/drawable/thinstashborder.xml b/androminion/res/drawable/thinstashborder.xml new file mode 100644 index 000000000..c83acbddb --- /dev/null +++ b/androminion/res/drawable/thinstashborder.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/androminion/res/layout/view_deck.xml b/androminion/res/layout/view_deck.xml index 41975c4ff..c8844daa3 100644 --- a/androminion/res/layout/view_deck.xml +++ b/androminion/res/layout/view_deck.xml @@ -11,14 +11,42 @@ android:layout_alignParentTop="true" android:textSize="12sp" /> - - + android:layout_below="@+id/name"> + + + + + + + + + Du darfst diese Karte zur Seite legen. Wenn du das tust: Lege eine Aktionskarte aus deiner Hand zur Seite, die bis zu 4 Geld kostet.\nZu Beginn deines Zuges: Spiele die zur Seite gelegte Aktionskarte. Sobald du sie ablegen musst, legst du sie stattdessen wieder zur Seite. Solltest du sie nicht ablegen müssen, legst du sie nicht wieder zur Seite. Die Wirkung der Karte Prinz wird sofort aufgehoben. Sie bleibt bis zum Spielende beiseitegelegt und kommt nicht mehr zum Einsatz. Schwarzmarkt Decke die obersten 3 Karten vom Schwarzmarkt-Stapel auf. Du darfst sofort eine der aufgedeckten Karten kaufen. Lege die nicht gekauften Karten in beliebiger Reihenfolge unter den Schwarzmarkt-Stapel zurück.\nSpielvorbereitung: Vor Spielbeginn wird ein Schwarzmarkt-Stapel gebildet. Dieser enthält jeweils eine Karte aller Königreichkarten, die nicht im Vorrat sind. + Geldversteck + Nachdem du deinen Ablagestapel gemischt hast, darfst du diese Karte an eine beliebige Stelle in deinen Nachziehstapel einsortieren. Einladung Nimm eine Aktionskarte, die bis zu 4 Geld kostet und lege sie zur Seite. Spiele sie zu Beginn deines nächsten Zuges. diff --git a/androminion/res/values-es/strings-cards.xml b/androminion/res/values-es/strings-cards.xml index c60af91ea..60900aec3 100644 --- a/androminion/res/values-es/strings-cards.xml +++ b/androminion/res/values-es/strings-cards.xml @@ -334,4 +334,6 @@ Gana una carta de Finca. Cada jugador (menos tú) gana una Maldición y se descarta hasta quedarse con 3 cartas en su mano. Corcel Fiel Elige dos opciones distintas: +2 Cartas; +2 Acciones; +(2); ganar 4 cartas de Plata y poner tu mazo en tu pila de descartes. + Alijo + Al barajar, puedes colocar esta carta en cualquier posición de tu mazo. diff --git a/androminion/res/values-fr/strings-cards.xml b/androminion/res/values-fr/strings-cards.xml index 3b4f77cf2..17935551a 100644 --- a/androminion/res/values-fr/strings-cards.xml +++ b/androminion/res/values-fr/strings-cards.xml @@ -496,8 +496,6 @@ Vous pouvez mettre de coté cette carte. Si vous le faites, mettez de coté une carte Action coûtant jusqu\'à 4 Pièces. Au début de chacun de vos tours, jouez cette carte Action, en la remettant de coté lorsque vous la défaussez du jeu. (Arrêtez de la jouer si vous ne pouvez pas la remettre de coté le même tour que vous l\'avez joué.) Village Fortifié Au début de votre phase Ajustement, si vous avez cette carte et aucune autre carte Action en jeu, vous pouvez placez cette carte sur le dessus de votre deck. - \ No newline at end of file diff --git a/androminion/res/values-ja/strings-cards.xml b/androminion/res/values-ja/strings-cards.xml index 10dc37a0c..3e3c05388 100644 --- a/androminion/res/values-ja/strings-cards.xml +++ b/androminion/res/values-ja/strings-cards.xml @@ -449,4 +449,7 @@ 他のプレイヤーは全員、自分のデッキの上から2枚のカードを公開し、その中のコスト(3) コイン~(6) コインのカード1枚を廃棄し、残りを捨て札にする。このカードによって騎士が廃棄された場合、このカードを廃棄する。\n---\nあなたはこのカードを廃棄したとき、金貨1枚を獲得する。 騎士 + + へそくり + When you shuffle, you may put this anywhere in your deck. diff --git a/androminion/res/values-nl/strings-cards.xml b/androminion/res/values-nl/strings-cards.xml index 583c4e1f3..e1fdc3c92 100644 --- a/androminion/res/values-nl/strings-cards.xml +++ b/androminion/res/values-nl/strings-cards.xml @@ -334,4 +334,6 @@ Pak een Landgoed. Iedere andere speler pakt een Vloek en legt af tot 3 kaarten. (Deze is niet in de voorraad) Vertrouwde Beiaard Kies 2 verschillende van de volgende opties: +2 Kaarten; +2 Acties; +2 Geld; pak 4 Zilver en leg je trekstapel op je aflegstapel. (Deze is niet in de voorraad) + Geldbuidel + Als je je aflegstapel schudt om een nieuwe trekstapel van te maken, mag je direct daarna de Geldbuidel naar een positie naar keuze in je trekstapel verplaatsen. diff --git a/androminion/res/values/attrs.xml b/androminion/res/values/attrs.xml index e55fa2cff..1698e9c5c 100644 --- a/androminion/res/values/attrs.xml +++ b/androminion/res/values/attrs.xml @@ -6,4 +6,5 @@ + \ No newline at end of file diff --git a/androminion/res/values/colors.xml b/androminion/res/values/colors.xml index 6b73d8507..81e5aa822 100644 --- a/androminion/res/values/colors.xml +++ b/androminion/res/values/colors.xml @@ -21,6 +21,9 @@ #806F49 #B0AFA7 #DDC492 + #E84C4C + #E84C4C + #E84C4C #d9562b #508db9 diff --git a/androminion/res/values/strings-cards.xml b/androminion/res/values/strings-cards.xml index a01fe5534..81cd6b120 100644 --- a/androminion/res/values/strings-cards.xml +++ b/androminion/res/values/strings-cards.xml @@ -605,6 +605,8 @@ You may set this aside. If you do, set aside an Action card from your hand costing up to 4 Coins. At the start of each of your turns, play that Action, setting it aside again when you discard it from play. (Stop playing it if you fail to set it aside on a turn you play it.) Black Market Reveal the top 3 cards of the Black Market deck. You may buy one of them immediately. Put the unbought cards on the bottom of the Black Market deck in any order.\n(Before the game, make a Black Market deck out of one copy of each Kingdom card not in the supply.) + Stash + When you shuffle, you may put this anywhere in your deck. Summon Gain an Action card costing up to 4 Coins. Set it aside. If you do, then at the start of your next turn, play it. diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index caa9ee793..48ece35d4 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -433,4 +433,14 @@ Gaining %1$s. Call card: %1$s resolved. Call card: Start of turn. Call card: + + Place Stash in deck + Place %1$s Stash cards in deck + On top + On bottom + Choose individually… + 1 card down + %1$s cards down + After cards to be drawn (%1$s) + Other… diff --git a/androminion/res/values/styles.xml b/androminion/res/values/styles.xml index f9160d566..fb0c6301f 100644 --- a/androminion/res/values/styles.xml +++ b/androminion/res/values/styles.xml @@ -8,6 +8,7 @@ @color/player4LineColor @color/player5LineColor @color/player6LineColor + @color/stashTextLight \ No newline at end of file diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index 6a6f0df81..d219dba8b 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -181,18 +181,19 @@ public void setCard(MyCard c) { if (viewstyle.equals("viewstyle-simple")) { if (c.isBane) { setBackgroundResource(R.drawable.thinbaneborder); + } else if (c.isStash) { + setBackgroundResource(R.drawable.thinstashborder); } else { setBackgroundResource(R.drawable.thinborder); } } else { if (c.isBane) { setBackgroundResource(R.drawable.baneborder); - } - else if (c.isShelter) - { - setBackgroundResource(R.drawable.shelterborder); - } - else { + } else if (c.isStash) { + setBackgroundResource(R.drawable.stashborder); + } else if (c.isShelter) { + setBackgroundResource(R.drawable.shelterborder); + } else { setBackgroundResource(R.drawable.cardborder); } } diff --git a/androminion/src/com/mehtank/androminion/ui/DeckView.java b/androminion/src/com/mehtank/androminion/ui/DeckView.java index 4bc3e50d0..675e0ad51 100644 --- a/androminion/src/com/mehtank/androminion/ui/DeckView.java +++ b/androminion/src/com/mehtank/androminion/ui/DeckView.java @@ -5,7 +5,9 @@ import android.graphics.Typeface; import android.preference.PreferenceManager; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.LayoutInflater; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; @@ -22,7 +24,15 @@ public class DeckView extends RelativeLayout { private TextView journeyToken; private TextView minusOneCoinToken; private TextView minusOneCardToken; - private TextView counts; + private LinearLayout counts; + private TextView countsPrefix; + private TextView countsDeck; + private TextView countsMiddle; + private TextView countsStashesInHand; + private TextView countsSuffix; + + private int textColor; + private int stashColor; private boolean showCardCounts = true; @@ -41,15 +51,27 @@ public DeckView(Context context, AttributeSet attrs) { journeyToken = (TextView) findViewById(R.id.journeyToken); minusOneCoinToken = (TextView) findViewById(R.id.minusOneCoinToken); minusOneCardToken = (TextView) findViewById(R.id.minusOneCardToken); - counts = (TextView) findViewById(R.id.counts); + counts = (LinearLayout) findViewById(R.id.counts); + countsPrefix = (TextView) findViewById(R.id.countsPrefix); + countsDeck = (TextView) findViewById(R.id.countsDeck); + countsMiddle = (TextView) findViewById(R.id.countsMiddle); + countsStashesInHand = (TextView) findViewById(R.id.countsStashesInHand); + countsSuffix = (TextView) findViewById(R.id.countsSuffix); if(PreferenceManager.getDefaultSharedPreferences(context).getBoolean("hide_card_counts", false)) { showCardCounts = false; counts.setVisibility(INVISIBLE); } + + TypedValue typedValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.stashTextColor, typedValue, true); + stashColor = typedValue.data; + + textColor = new TextView(context).getTextColors().getDefaultColor(); + } - public void set(String nameStr, int turns, int deckSize, int handSize, int numCards, + public void set(String nameStr, int turns, int deckSize, boolean stashOnDeck, int handSize, int stashesInHand, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight, boolean showColor, int color) { @@ -108,10 +130,12 @@ public void set(String nameStr, int turns, int deckSize, int handSize, int numCa minusOneCoinToken.setVisibility(INVISIBLE); if(showCardCounts) { - String str = "{ \u2261 " + deckSize + - " \u261e " + handSize + - " \u03a3 " + numCards + " }"; - counts.setText(str); + countsPrefix.setText("{ "); + countsDeck.setText("\u2261 "); + countsDeck.setTextColor(stashOnDeck ? stashColor : textColor); + countsMiddle.setText(deckSize + " \u261e " + handSize); + countsStashesInHand.setText(stashesInHand == 0 ? "" : " (" + stashesInHand + ")"); + countsSuffix.setText(" \u03a3 " + numCards + " }"); } } } diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index e59531bf9..ed3f743a5 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -1017,7 +1017,7 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { for (int i=0; i deckSize) { + return getString(R.string.stash_on_bottom); + } else { + return format(R.string.stash_after_cards_to_draw, cardsToDraw); + } + } else if (option == StashOption.PlaceOther) { + return getString(R.string.stash_more_options); + } } else if (option instanceof PutBackOption) { if (option == PutBackOption.Action) { return getString(R.string.putback_option_two); diff --git a/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java b/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java index 01568c85d..f55d04f72 100644 --- a/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java +++ b/androminion/src/com/mehtank/androminion/util/PlayerAdapter.java @@ -50,7 +50,7 @@ public View getView(int pos, View origView, ViewGroup parent) { dv = (DeckView) origView; } ps = getItem(pos); - dv.set(ps.name, ps.turns, ps.deckSize, ps.handSize, ps.numCards, ps.pt, ps.vt, ps.gct, ps.minusOneCoinTokenOn, ps.minusOneCardTokenOn, ps.journeyTokenFaceUp, ps.highlight, ps.showColor, ps.color); + dv.set(ps.name, ps.turns, ps.deckSize, ps.stashOnDeck, ps.handSize, ps.stashesInHand, ps.numCards, ps.pt, ps.vt, ps.gct, ps.minusOneCoinTokenOn, ps.minusOneCardTokenOn, ps.journeyTokenFaceUp, ps.highlight, ps.showColor, ps.color); return dv; } diff --git a/androminion/src/com/mehtank/androminion/util/PlayerSummary.java b/androminion/src/com/mehtank/androminion/util/PlayerSummary.java index c1560872a..3d4131a14 100644 --- a/androminion/src/com/mehtank/androminion/util/PlayerSummary.java +++ b/androminion/src/com/mehtank/androminion/util/PlayerSummary.java @@ -13,7 +13,9 @@ public class PlayerSummary { public String name; public String realName; public int deckSize; + public boolean stashOnDeck; public int handSize; + public int stashesInHand; public int numCards; public int pt; public int vt; @@ -30,11 +32,13 @@ public PlayerSummary(String name) { this.name = name; } - public void set(String name, int turns, int deckSize, int handSize, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight, boolean showColor, int color){ + public void set(String name, int turns, int deckSize, boolean stashOnDeck, int handSize, int stashesInHand, int numCards, int pt, int vt, int gct, boolean minusOneCoinTokenOn, boolean minusOneCardTokenOn, boolean journeyTokenFaceUp, boolean highlight, boolean showColor, int color){ this.name = name; this.turns = turns; this.deckSize = deckSize; + this.stashOnDeck = stashOnDeck; this.handSize = handSize; + this.stashesInHand = stashesInHand; this.numCards = numCards; this.pt = pt; this.vt = vt; diff --git a/vdom/src/com/vdom/comms/GameStatus.java b/vdom/src/com/vdom/comms/GameStatus.java index e80c3fe4d..33298a1ea 100644 --- a/vdom/src/com/vdom/comms/GameStatus.java +++ b/vdom/src/com/vdom/comms/GameStatus.java @@ -6,7 +6,7 @@ public class GameStatus implements Serializable { - private static final long serialVersionUID = -8819195521987453596L; + private static final long serialVersionUID = -1192478381540599643L; public int whoseTurn; public String name; @@ -29,7 +29,9 @@ public class GameStatus implements Serializable { public int[][][] tokens; public int[] costs; public int[] deckSizes; + public boolean[] stashOnDeck; public int[] handSizes; + public int[] stashesInHand; public int[] numCards; public int[] pirates; public int[] victoryTokens; @@ -66,7 +68,9 @@ public class GameStatus implements Serializable { public GameStatus setTokens(int[][][] is) {tokens = is; return this;}; public GameStatus setCosts(int[] is) {costs = is; return this;}; public GameStatus setDeckSizes(int[] is) {deckSizes = is; return this;}; + public GameStatus setStashOnDeck(boolean[] is) {stashOnDeck = is; return this;}; public GameStatus setHandSizes(int[] is) {handSizes = is; return this;}; + public GameStatus setStashesInHand(int[] is) {stashesInHand = is; return this;}; public GameStatus setNumCards(int[] is) {numCards = is; return this;} public GameStatus setPirates(int[] is) {pirates = is; return this;} public GameStatus setVictoryTokens(int[] is) {victoryTokens = is; return this;} diff --git a/vdom/src/com/vdom/comms/MyCard.java b/vdom/src/com/vdom/comms/MyCard.java index e870594a1..cd17cf1de 100644 --- a/vdom/src/com/vdom/comms/MyCard.java +++ b/vdom/src/com/vdom/comms/MyCard.java @@ -44,6 +44,7 @@ public class MyCard implements Serializable { public boolean isReserve = false; public boolean isTraveller = false; public boolean isBlackMarket = false; + public boolean isStash = false; public static final int SUPPLYPILE = 1; public static final int MONEYPILE = 2; diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index df543c220..97a29664c 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -18,7 +18,6 @@ import com.vdom.api.GameEventListener; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; -import com.vdom.core.Player.ExtraTurnOption; public abstract class BasePlayer extends Player implements GameEventListener { //trash in this order! @@ -2697,6 +2696,13 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { Card[] left = cl.sort(new Util.CardCostComparatorDesc()); return left[0]; } + + @Override + public int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw) { + if (context.attackedPlayer == this) + return cardsToDraw; + return 0; + } @Override public boolean survivors_shouldDiscardTopCards(MoveContext context, Card[] array) { diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index da81048bf..7c80f14f9 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -87,7 +87,7 @@ public enum Type { VirtualEvents, // Promo Cards - Envoy, Governor, WalledVillage, Prince, BlackMarket, Summon, + Envoy, Governor, WalledVillage, Prince, BlackMarket, Stash, Summon, // Promo Cards (not yet implemented) // Stash // Victory Token card container @@ -426,6 +426,7 @@ public enum Type { public static final Card envoy; public static final Card prince; public static final Card blackMarket; + public static final Card stash; public static final Card summon; static { @@ -771,6 +772,7 @@ public enum Type { actionCardsPromo.add(envoy = new ActionCardImpl.Builder(Cards.Type.Envoy, 4).description("Reveal the top 5 cards of your deck. The player to your left chooses one for you to discard. Draw the rest.").expansion("Promo").build()); actionCardsPromo.add(prince = new ActionCardImpl.Builder(Cards.Type.Prince, 8).description("You may set this aside. If you do, set aside an Action card from your hand costing up to 4 Coins. At the start of each of your turns, play that Action, setting it aside again when you discard it from play. (Stop playing it if you fail to set it aside on a turn you play it.)").expansion("Promo").build()); actionCardsPromo.add(blackMarket = new ActionCardImpl.Builder(Cards.Type.BlackMarket, 3).addGold(2).description("Reveal the top 3 cards of the Black Market deck. You may buy one of them immediately. Put the unbought cards on the bottom of the Black Market deck in any order./n(Before the game, make a Black Market deck out of one copy of each Kingdom card not in the supply.)").expansion("Promo").build()); + actionCardsPromo.add(stash = new TreasureCardImpl.Builder(Cards.Type.Stash, 5, 2).description("When you shuffle, you may put this anywhere in your deck.").expansion("Promo").build()); eventCardsPromo.add(summon = new EventCardImpl.Builder(Cards.Type.Summon, 5).isEvent().description("Gain an Action card costing up to 4 Coins. Set it aside. If you do, then at the start of your next turn, play it.").expansion("Promo").build()); // Collect all Expansions diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index bc76c76b9..7f3bd0c1e 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1686,9 +1686,9 @@ Card draw(Player player) { } public void replenishDeck(Player player) { - player.replenishDeck(); - - MoveContext context = new MoveContext(this, player); + MoveContext context = new MoveContext(this, player); + player.replenishDeck(context); + GameEvent event = new GameEvent(GameEvent.Type.DeckReplenished, context); broadcastEvent(event); } @@ -1934,7 +1934,7 @@ protected void initPlayerCards() { player.discard.remove(card); player.hand.add(card); } - player.replenishDeck(); + player.replenishDeck(null); } } @@ -2104,9 +2104,6 @@ protected void initCards() { break; Card c = null; int replacementCost = -1; - if(s.equalsIgnoreCase("stash")) { - replacementCost = 5; - } if(replacementCost != -1) { ArrayList cardsWithSameCost = new ArrayList(); @@ -2637,7 +2634,7 @@ public void gameEvent(GameEvent event) { player.discard.remove(c); player.deck.add(c); } - player.shuffleDeck(); + player.shuffleDeck(context); } } else if (event.card.equals(Cards.borderVillage)) { boolean validCard = false; diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index cfbd47355..5652311b6 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -43,6 +43,8 @@ public boolean selectBoolean(MoveContext context, Card cardResponsible) { public static final String OPTION_CALL_WHEN_GAIN = "CALLWHENGAIN"; public static final String OPTION_CALL_RESOLVE_ACTION = "CALLAFTERACTION"; public static final String OPTION_START_TURN_EFFECT = "STARTTURN"; + public static final String OPTION_STASH = "PLACESTASH"; + public static final String OPTION_STASH_POSITION = "PLACESTASHPOS"; abstract protected int selectOption(MoveContext context, Card card, Object[] options); abstract protected int[] orderCards(MoveContext context, int[] cards); @@ -2236,6 +2238,57 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { return cards[selectOption(context, Cards.envoy, options)]; } + public enum StashOption { + PlaceOnTop, + PlaceAfterCardsToDraw, + PlaceOther + } + + @Override + public int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw) { + if(context.isQuickPlay() && shouldAutoPlay_stash_chooseDeckPosition(context, deckSize, numStashes, cardsToDraw)) { + return super.stash_chooseDeckPosition(context, deckSize, numStashes, cardsToDraw); + } + // Simple options first + Object[] options = new Object[7]; + options[0] = OPTION_STASH; + options[1] = deckSize; + options[2] = numStashes; + options[3] = cardsToDraw; + options[4] = StashOption.PlaceOnTop; + options[5] = StashOption.PlaceAfterCardsToDraw; + options[6] = StashOption.PlaceOther; + + StashOption option = (StashOption) options[selectOption(context, Cards.stash, options) + 4]; + if (option == StashOption.PlaceOnTop) { + return 0; + } else if (option == StashOption.PlaceAfterCardsToDraw) { + if (cardsToDraw > deckSize) + return deckSize; + return cardsToDraw; + } + // advanced options if player chose other + if (numStashes > 1) { + options = new Object[deckSize + 6]; + options[0] = OPTION_STASH_POSITION; + options[1] = deckSize; + options[2] = numStashes; + for (int i = 3; i < options.length; ++i) { + options[i] = i - 5; + } + return (Integer) options[selectOption(context, Cards.stash, options) + 3]; + } + + options = new Object[deckSize + 5]; + options[0] = OPTION_STASH_POSITION; + options[1] = deckSize; + options[2] = numStashes; + for (int i = 3; i < options.length; ++i) { + options[i] = i - 4; + } + return (Integer) options[selectOption(context, Cards.stash, options) + 3]; + } + @Override public boolean survivors_shouldDiscardTopCards(MoveContext context, Card[] cards) { if(context.isQuickPlay() && shouldAutoPlay_navigator_shouldDiscardTopCards(context, cards)) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index b2c5dd55c..ae7bee909 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -474,6 +474,18 @@ public void debug(String msg) { public CardList getHand() { return hand; } + + public int getStashesInHand() { + if (hand.size() == 0) + return 0; + int result = 0; + for (Card c : hand) { + if (c.equals(Cards.stash)) { + result++; + } + } + return result; + } public CardList getDiscard() { return discard; @@ -482,6 +494,12 @@ public CardList getDiscard() { public int getDeckSize() { return deck.size(); } + + public boolean isStashOnDeck() { + if (deck.size() == 0) + return false; + return deck.get(0).equals(Cards.stash); + } public int getDiscardSize() { return discard.size(); @@ -808,21 +826,78 @@ public void putOnTopOfDeck(Card card) { deck.add(0, card); } - public void replenishDeck() { + public void replenishDeck(MoveContext context) { shuffleCount++; - while (discard.size() > 0) { - deck.add(discard.remove(Game.rand.nextInt(discard.size()))); + shuffleIntoDeck(context, discard); + } + + private void shuffleIntoDeck(MoveContext context, CardList source) { + int cardsLeftToDraw = 5; //TODO - dominionator - do this and don't forget to account for -1 card token + ArrayList stashes = new ArrayList(); + int positionAll = -1; + if (context != null) { + int numStashes = 0; + for (Card c : source) { + if (c.equals(Cards.stash)) { + numStashes++; + } + } + boolean shuffleNormally = false; + if (source.size() == numStashes) { + shuffleNormally = true; + } else if (numStashes > 1) { + positionAll = this.controlPlayer.stash_chooseDeckPosition(context, source.size() - numStashes, numStashes, cardsLeftToDraw); + // -1 -> Pass (shuffle normally) + // -2 or below -> (choose individually) + if (positionAll > source.size() - numStashes) + positionAll = -1; + if (positionAll == -1) { + shuffleNormally = true; + } + } + if (!shuffleNormally) { + //pull out the Stash cards + for (int i = 0; i < source.size(); ++i) { + if (source.get(i).equals(Cards.stash)) { + stashes.add(source.remove(i--)); + } + } + } + } + + // shuffle + while (source.size() > 0) { + deck.add(source.remove(Game.rand.nextInt(source.size()))); } + + while (stashes.size() > 0) { + source.add(stashes.remove(0)); + } + + // add pulled Stash cards back into deck + if (source.size() > 0) { + int numStashes = source.size(); + for (int i = 0; i < numStashes; ++i) { + int position; + if (positionAll >= 0) { + position = positionAll; + } else { + position = controlPlayer.stash_chooseDeckPosition(context, deck.size(), 1, cardsLeftToDraw); + if (position < 0) + position = Game.rand.nextInt(deck.size() + 1); + position = Math.min(position, deck.size()); + } + deck.add(position, source.remove(0)); + } + } } - public void shuffleDeck() { - ArrayList tempDeck = new ArrayList(); + public void shuffleDeck(MoveContext context) { + CardList tempDeck = new CardList(this, name); while (deck.size() > 0) { - tempDeck.add(deck.remove(Game.rand.nextInt(deck.size()))); - } - for(Card c : tempDeck) { - deck.add(c); + tempDeck.add(deck.remove(0)); } + shuffleIntoDeck(context, tempDeck); } public void checkCardsValid() { @@ -831,9 +906,6 @@ public void checkCardsValid() { deck.checkValid(); } - // protected void discardRemainingCardsFromHand(MoveContext context, Card[] cardsToKeep) { - // discardRemainingCardsFromHand(context, cardsToKeep, null, -1); - // } protected void discardRemainingCardsFromHand(MoveContext context, Card[] cardsToKeep, Card responsibleCard, int keepCardCount) { ArrayList keepCards = new ArrayList(Arrays.asList(cardsToKeep)); @@ -1765,7 +1837,9 @@ public ArrayList getActionsInHand() { public abstract Card governor_cardToObtain(MoveContext context, int exactCost, boolean potion); public abstract Card envoy_cardToDiscard(MoveContext context, Card[] revealedCards); - + + public abstract int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw); + public abstract boolean survivors_shouldDiscardTopCards(MoveContext context, Card[] array); public abstract Card[] survivors_cardOrder(MoveContext context, Card[] array); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 0b709782f..41cc9e16c 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -779,6 +779,10 @@ public boolean shouldAutoPlay_selectPutBackOption(MoveContext context, List Date: Mon, 18 Jan 2016 17:24:57 -0700 Subject: [PATCH 040/141] Stash Promo card. Adding cards to draw to message to be easliy able to put Stash card(s) after cards you're going to automatically draw. --- .../com/mehtank/androminion/ui/Strings.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 252 +++++++++--------- .../com/vdom/core/CallableActionCardImpl.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/Game.java | 28 +- vdom/src/com/vdom/core/Player.java | 20 +- vdom/src/com/vdom/core/TreasureCardImpl.java | 2 +- vdom/src/com/vdom/core/Util.java | 4 +- vdom/src/com/vdom/core/VictoryCardImpl.java | 2 +- 9 files changed, 157 insertions(+), 157 deletions(-) diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index e9990b115..3f87c7178 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -849,7 +849,7 @@ public static String getOptionText(Object option, Object[] extras) { } else if (option == StashOption.PlaceAfterCardsToDraw) { int deckSize = (Integer) extras[1]; int cardsToDraw = (Integer) extras[3]; - if (cardsToDraw > deckSize) { + if (cardsToDraw >= deckSize) { return getString(R.string.stash_on_bottom); } else { return format(R.string.stash_after_cards_to_draw, cardsToDraw); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 1b8c6c221..35f991083 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -249,21 +249,17 @@ public void play(Game game, MoveContext context, boolean fromHand) { if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCoin)) context.addCoins(1); if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCard)) - game.drawToHand(currentPlayer, actualCard); + game.drawToHand(currentPlayer, actualCard, 1 + addCards); context.actions += addActions; context.buys += addBuys; context.addCoins(addGold); currentPlayer.addVictoryTokens(context, addVictoryTokens); - int cardsToDraw = addCards; - while (cardsToDraw > 0) { - cardsToDraw--; - game.drawToHand(currentPlayer, this); + for (int i = 0; i < addCards; ++i) { + game.drawToHand(currentPlayer, this, addCards - i); } - - additionalCardActions(game, context, currentPlayer); event = new GameEvent(GameEvent.Type.PlayedAction, (MoveContext) context); @@ -993,7 +989,7 @@ private void embargo(Game game, MoveContext context, Player currentPlayer) { private void navigator(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 5 - i); if (card != null) { topOfTheDeck.add(card); } @@ -1046,7 +1042,7 @@ private void navigator(Game game, MoveContext context, Player currentPlayer) { private void lookout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 3 - i); if (card != null) { cards.add(card); } @@ -1098,8 +1094,8 @@ private void lookout(Game game, MoveContext context, Player currentPlayer) { } private void pearlDiver(MoveContext context, Player currentPlayer) { - if (currentPlayer.getDeckSize() <= 1 && currentPlayer.discard.size() + currentPlayer.getDeckSize() > 1) { - context.game.replenishDeck(currentPlayer); + if (currentPlayer.getDeckSize() == 0 && currentPlayer.discard.size() > 0) { + context.game.replenishDeck(currentPlayer, 0); } if (currentPlayer.getDeckSize() > 1) { @@ -1252,7 +1248,7 @@ private void nativeVillage(Game game, MoveContext context, Player currentPlayer) currentPlayer.hand.add(currentPlayer.nativeVillage.remove(0)); } } else { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, 1); if (draw != null) { currentPlayer.nativeVillage.add(draw); Util.sensitiveDebug(currentPlayer, "Added to Native Village:" + draw.getName(), true); @@ -1266,7 +1262,7 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - Card draw = game.draw(player); + Card draw = game.draw(player, 1); if (draw != null) { player.discard(draw, this.controlCard, playerContext); } @@ -1279,7 +1275,7 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { private void councilRoom(Game game, MoveContext context) { for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - drawToHand(game, player, this.controlCard); + game.drawToHand(player, this.controlCard, 1); } } } @@ -1338,8 +1334,9 @@ private void apprentice(Game game, MoveContext context, Player currentPlayer) { currentPlayer.hand.remove(cardToTrash); currentPlayer.trash(cardToTrash, this.controlCard, context); - for (int i = 1; i <= (cardToTrash.getCost(context) + (cardToTrash.costPotion() ? 2 : 0)); i++) { - game.drawToHand(currentPlayer, this.controlCard); + int cardsToDraw = (cardToTrash.getCost(context) + (cardToTrash.costPotion() ? 2 : 0)); + for (int i = 1; i <= cardsToDraw; i++) { + game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i); } } } @@ -1368,7 +1365,7 @@ private void transmute(MoveContext context, Player currentPlayer) { private void apothecary(Game game, MoveContext context, Player currentPlayer) { ArrayList residue = new ArrayList(); for (int i = 1; i <= 4; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 4 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); if (card.equals(Cards.copper) || card.equals(Cards.potion)) { @@ -1482,7 +1479,7 @@ private void torturer(Game game, MoveContext context, Player currentPlayer) { private void scout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 4 - i); if (card == null) { break; } @@ -1690,7 +1687,7 @@ private void bishop(Game game, MoveContext context, Player currentPlayer) { private void city(Game game, MoveContext context, Player currentPlayer) { if (game.emptyPiles() > 0) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 1); } if (game.emptyPiles() > 1) { context.buys++; @@ -1916,7 +1913,7 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(player); + Card card = game.draw(player, 3 - i); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -2034,7 +2031,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { } if (numberOfCardsDiscarded == 2) { - game.drawToHand(player, this.controlCard); + game.drawToHand(player, this.controlCard, 1); } } } @@ -2042,10 +2039,11 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { } private void watchTower(Game game, MoveContext context, Player currentPlayer) { - while (currentPlayer.hand.size() < 6) { - if(!game.drawToHand(currentPlayer, this.controlCard)) + int cardsToDraw = 6 - currentPlayer.hand.size(); + for (int i = 0; i < cardsToDraw; ++i) { + if(!game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i)) break; - } + } } private void farmingVillage(Game game, MoveContext context, Player currentPlayer) { @@ -2053,7 +2051,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(currentPlayer)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(currentPlayer, -1)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -2078,7 +2076,7 @@ private void fortuneTeller(Game game, MoveContext context, Player currentPlayer) ArrayList cardsToDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(player)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { + while ((draw = game.draw(player, -1)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { player.reveal(draw, this.controlCard, playerContext); cardsToDiscard.add(draw); } @@ -2115,7 +2113,7 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { HashSet cardNames = new HashSet(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 4; i++) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, 4 - i); if (draw == null) { break; } @@ -2165,7 +2163,7 @@ private void jester(Game game, MoveContext context, Player currentPlayer) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); - Card draw = game.draw(targetPlayer); + Card draw = game.draw(targetPlayer, 1); Card virtCard = draw; if (draw == null) @@ -2216,7 +2214,7 @@ private void huntingParty(Game game, MoveContext context, Player currentPlayer) ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer)) != null && cardNames.contains(draw.getName())) { + while ((draw = game.draw(currentPlayer, -1)) != null && cardNames.contains(draw.getName())) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -2241,7 +2239,7 @@ private void crossroads(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < victoryCards; i++) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, victoryCards - i); } int crossroadsPlayed = this.controlCard.numberTimesAlreadyPlayed; @@ -2264,7 +2262,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { context.actions += 2; } else if (option == TrustySteedOption.AddCards) { for (int i = 0; i < 2; i++) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2 - i); } } else if (option == TrustySteedOption.AddGold) { context.addCoins(2); @@ -2287,7 +2285,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { private void duchess(Game game, MoveContext context) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - Card c = game.draw(targetPlayer); + Card c = game.draw(targetPlayer, 1); if(c != null) { MoveContext targetPlayerContext = new MoveContext(context, game, targetPlayer); boolean discard = (targetPlayer).controlPlayer.duchess_shouldDiscardCardFromTopOfDeck(targetPlayerContext, c); @@ -2321,8 +2319,8 @@ private void spiceMerchant(Game game, MoveContext context, Player currentPlayer) SpiceMerchantOption option = currentPlayer.controlPlayer.spiceMerchant_chooseOption(context); if(option == SpiceMerchantOption.AddCardsAndAction) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); context.actions += 1; } else { @@ -2356,7 +2354,7 @@ private void trader(MoveContext context, Player currentPlayer) { private void cartographer(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 4 - i); if (card != null) { topOfTheDeck.add(card); } @@ -2535,8 +2533,8 @@ private void steward(Game game, MoveContext context, Player currentPlayer) { if (option == Player.StewardOption.AddGold) { context.addCoins(2); } else if (option == Player.StewardOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); } else if (option == Player.StewardOption.TrashCards) { CardList hand = currentPlayer.getHand(); if (hand.size() == 0) { @@ -2593,7 +2591,7 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer); + Card card = game.draw(targetPlayer, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -2755,7 +2753,7 @@ private void menagerie(Game game, MoveContext context, Player currentPlayer) { int numCards = distinct ? 3 : 1; for (int i = 0; i < numCards; i++) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, numCards - i); } } @@ -2809,7 +2807,7 @@ private void tournament(Game game, MoveContext context, Player currentPlayer) { } if (!opponentsRevealedProvince) { - game.drawToHand(currentPlayer, this); + game.drawToHand(currentPlayer, this, 1); context.addCoins(1); } } @@ -2952,10 +2950,10 @@ private void minion(Game game, MoveContext context, Player currentPlayer) { player.discard(player.hand.remove(0), this.controlCard, targetContext); } - game.drawToHand(player, this.controlCard); - game.drawToHand(player, this.controlCard); - game.drawToHand(player, this.controlCard); - game.drawToHand(player, this.controlCard); + game.drawToHand(player, this.controlCard, 4); + game.drawToHand(player, this.controlCard, 3); + game.drawToHand(player, this.controlCard, 2); + game.drawToHand(player, this.controlCard, 1); } } } @@ -2972,7 +2970,7 @@ private void pawn(Game game, MoveContext context, Player currentPlayer) { } else if (option == Player.PawnOption.AddBuy) { context.buys++; } else if (option == Player.PawnOption.AddCard) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 1); } else if (option == Player.PawnOption.AddGold) { context.addCoins(1); } @@ -2990,7 +2988,7 @@ private void saboteur(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw; - while ((draw = game.draw(player)) != null) { + while ((draw = game.draw(player, -1)) != null) { if (draw.getCost(context) >= 3) { int value = draw.getCost(context); value -= 2; @@ -3039,8 +3037,8 @@ private void shantyTown(Game game, MoveContext context, Player currentPlayer) { } if (!actions) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); } } @@ -3088,7 +3086,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla } MoveContext playerContext = new MoveContext(game, player); - Card card = game.draw(player); + Card card = game.draw(player, 1); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -3115,7 +3113,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla ArrayList cardsToPutInHand = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer)) != null) { + while ((draw = game.draw(currentPlayer, -1)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); if(!(draw instanceof ActionCard)) { @@ -3132,7 +3130,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla private void conspirator(Game game, MoveContext context, Player currentPlayer) { if (context.actionsPlayedSoFar >= 3) { context.actions++; - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 1); } } @@ -3148,7 +3146,7 @@ private void wishingWell(Game game, MoveContext context, Player currentPlayer) { if (!options.isEmpty()) { Card card = currentPlayer.controlPlayer.wishingWell_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(card, this.controlCard, context); - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -3199,7 +3197,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 1); } } } @@ -3213,9 +3211,9 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { if (option == Player.NoblesOption.AddActions) { context.actions += 2; } else if (option == Player.NoblesOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 3); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); } } } @@ -3223,8 +3221,8 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { private void tribute(Game game, MoveContext context, Player currentPlayer) { Card[] revealedCards = new Card[2]; Player nextPlayer = game.getNextPlayer(); - revealedCards[0] = game.draw(nextPlayer); - revealedCards[1] = game.draw(nextPlayer); + revealedCards[0] = game.draw(nextPlayer, 2); + revealedCards[1] = game.draw(nextPlayer, 1); if (revealedCards[0] != null) { nextPlayer.reveal(revealedCards[0], this.controlCard, new MoveContext(game, nextPlayer)); @@ -3250,8 +3248,8 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { context.addCoins(2); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); } } } @@ -3267,7 +3265,7 @@ private void swindler(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - Card draw = game.draw(player); + Card draw = game.draw(player, 1); if (draw != null) { player.trash(draw, this.controlCard, playerContext); @@ -3408,7 +3406,7 @@ private void stables(Game game, MoveContext context, Player currentPlayer) { context.actions++; for (int i = 0; i < 3; i++) { - if(!game.drawToHand(currentPlayer, this.controlCard)) { + if(!game.drawToHand(currentPlayer, this.controlCard, 3 - i)) { break; } } @@ -3422,7 +3420,7 @@ private void margrave(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - game.drawToHand(player, this.controlCard); + game.drawToHand(player, this.controlCard, 1); int keepCardCount = 3; if (player.hand.size() > keepCardCount) { @@ -3440,7 +3438,7 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { MoveContext targetContext = new MoveContext(game, targetPlayer); ArrayList cards = new ArrayList(); for(int i=0; i < 2; i++) { - Card c = game.draw(targetPlayer); + Card c = game.draw(targetPlayer, 2 - i); if(c == null) { break; } @@ -3489,7 +3487,7 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < 2; i++) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2 - i); } } @@ -3510,7 +3508,7 @@ private void oasis(MoveContext context, Player currentPlayer) { private void jackOfAllTrades(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); - Card c = game.draw(currentPlayer); + Card c = game.draw(currentPlayer, 1); if(c != null) { boolean discard = currentPlayer.controlPlayer.jackOfAllTrades_shouldDiscardCardFromTopOfDeck(context, c); if(discard) { @@ -3519,12 +3517,14 @@ private void jackOfAllTrades(Game game, MoveContext context, Player currentPlaye currentPlayer.putOnTopOfDeck(c); } } - while(currentPlayer.hand.size() < 5) { - if(!game.drawToHand(currentPlayer, this.controlCard)) { + + int cardsToDraw = 5 - currentPlayer.hand.size(); + for (int i = 0; i < cardsToDraw; ++i) { + if(!game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i)) { break; } } - + Card cardToTrash = currentPlayer.controlPlayer.jackOfAllTrades_nonTreasureToTrash(context); if(cardToTrash != null) { if(!currentPlayer.hand.contains(cardToTrash) || cardToTrash instanceof TreasureCard) { @@ -3668,9 +3668,8 @@ private void cellar(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Cellar discard error, trying to discard cards not in hand, ignoring extra."); } - while (numberOfCards > 0) { - numberOfCards--; - game.drawToHand(currentPlayer, this.controlCard); + for (int i = 0; i < numberOfCards; ++i) { + game.drawToHand(currentPlayer, this.controlCard, numberOfCards - i); } } } @@ -3746,7 +3745,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { ArrayList toOrder = new ArrayList(); while (toOrder.size() < 2) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, -1); if (draw == null) { break; } @@ -3807,7 +3806,7 @@ private void adventurer(Game game, MoveContext context, Player currentPlayer) { int treasureCardsRevealed = 0; while (treasureCardsRevealed < 2) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, -1); if (draw == null) { break; } @@ -3832,7 +3831,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { // we need to manually remove the minus one card token currentPlayer.setMinusOneCardToken(false, context); while (currentPlayer.hand.size() < 7) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, -1); if (draw == null) { break; } @@ -3914,7 +3913,7 @@ private void pirateShip(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer); + Card card = game.draw(targetPlayer, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4010,7 +4009,7 @@ private void chancellor(Game game, MoveContext context, Player currentPlayer) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); } } } @@ -4125,20 +4124,16 @@ protected CardList haven(Player player) { protected void drawToHand(Game game, Player player, Card responsible, int count) { for (int i=0; i < count; i++) { - game.drawToHand(player, responsible); + game.drawToHand(player, responsible, count - i); } } - protected void drawToHand(Game game, Player player, Card responsible) { - game.drawToHand(player, responsible); - } - protected void addToHand(Player player, Card card) { player.hand.add(card); } - protected Card draw(Game game, Player player) { - return game.draw(player); + protected Card draw(Game game, Player player, int cardsLeftToDraw) { + return game.draw(player, cardsLeftToDraw); } protected Player[] getAllPlayers() { @@ -4229,7 +4224,7 @@ public void nobleBrigandAttack(MoveContext moveContext, boolean defensible) { List cardsToDiscard = new ArrayList(); for (int j = 0; j < 2; j++) { - Card card = context.game.draw(targetPlayer); + Card card = context.game.draw(targetPlayer, 2 - j); if(card == null) { break; } @@ -4322,7 +4317,7 @@ private void sage(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer)) != null && draw.getCost(context) < 3) { + while ((draw = game.draw(currentPlayer, -1)) != null && draw.getCost(context) < 3) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -4431,7 +4426,7 @@ public void beggar(Player currentPlayer, MoveContext context) { public void catacombs(Game game, Player currentPlayer, MoveContext context) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 3 - i); if (card != null) { topOfTheDeck.add(card); } @@ -4442,9 +4437,9 @@ public void catacombs(Game game, Player currentPlayer, MoveContext context) { while (!topOfTheDeck.isEmpty()) { currentPlayer.discard(topOfTheDeck.remove(0), this.controlCard, context); } - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 3); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); } else { // Put the cards in hand for (Card c : topOfTheDeck) { @@ -4626,7 +4621,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { } private void ironmonger(Game game, Player currentPlayer, MoveContext context) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 1); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -4643,7 +4638,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 1); } } } @@ -4672,7 +4667,7 @@ private void mystic(Game game, MoveContext context, Player currentPlayer) { if (options.size() > 0) { Card toName = currentPlayer.controlPlayer.mystic_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(toName, this.controlCard, context); - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -4698,7 +4693,7 @@ private void scavenger(Game game, MoveContext context, Player currentPlayer) game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); } } @@ -4737,9 +4732,8 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Storeroom discard error, trying to discard cards not in hand, ignoring extra."); } - while (numberOfCards > 0) { - numberOfCards--; - game.drawToHand(currentPlayer, this.controlCard); + for (int i = 0; i < numberOfCards; ++i) { + game.drawToHand(currentPlayer, this.controlCard, numberOfCards - i); } } @@ -4771,7 +4765,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { private void wanderingMinstrel(Player currentPlayer, MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = context.game.draw(currentPlayer); + Card card = context.game.draw(currentPlayer, 3 - i); if (card == null) { break; } @@ -4810,7 +4804,7 @@ private void rebuild(Player currentPlayer, MoveContext context) { Card last = null; // search for first Victory card that was not named - while ((last = context.game.draw(currentPlayer)) != null) { + while ((last = context.game.draw(currentPlayer, -1)) != null) { if (last instanceof VictoryCard && !last.equals(named)) break; cards.add(last); currentPlayer.reveal(last, this.controlCard, context); @@ -4859,7 +4853,7 @@ private void rogue(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer); + Card card = game.draw(targetPlayer, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4947,12 +4941,12 @@ private void governor(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Governor option error, ignoring."); } else { if (option == Player.GovernorOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 3); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - drawToHand(game, player, this.controlCard); + game.drawToHand(player, this.controlCard, 1); } } } else if (option == Player.GovernorOption.GainTreasure) { @@ -5020,7 +5014,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); Player nextPlayer = game.getNextPlayer(); for (int i = 0; i < 5; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 5 - i); if (card != null) { cards.add(card); currentPlayer.reveal(card, this.controlCard, context); @@ -5059,7 +5053,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { public void isTrashed(MoveContext context) { switch (this.controlCard.behaveAsCard().getType()) { case Rats: - context.game.drawToHand(context.player, this.controlCard, true); + context.game.drawToHand(context.player, this.controlCard, 1, true); break; case Squire: // Need to ensure that there is at least one Attack card that can be gained, @@ -5132,9 +5126,9 @@ else if (gainEstates) context.player.hand.add(this.controlCard); break; case Cultist: - context.game.drawToHand(context.player, this.controlCard, false); - context.game.drawToHand(context.player, this.controlCard, false); - context.game.drawToHand(context.player, this.controlCard, false); + context.game.drawToHand(context.player, this.controlCard, 3, false); + context.game.drawToHand(context.player, this.controlCard, 2, false); + context.game.drawToHand(context.player, this.controlCard, 1, false); break; case SirVander: context.player.controlPlayer.gainNewCard(Cards.gold, this.controlCard, context); @@ -5204,7 +5198,7 @@ public boolean isTraveller() { private void survivors(MoveContext context, Game game, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 2 - i); if (card != null) { topOfTheDeck.add(card); } @@ -5320,8 +5314,8 @@ private void mercenary(MoveContext context, Game game, Player currentPlayer) if (cardsTrashedCount == 2) { - game.drawToHand(currentPlayer, this.controlCard); - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 2); + game.drawToHand(currentPlayer, this.controlCard, 1); context.addCoins(2); @@ -5420,14 +5414,14 @@ private void madman(MoveContext context, Game game, Player currentPlayer) { int handSize = currentPlayer.hand.size(); for (int i = 0; i < handSize; ++i) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, handSize - i); } } } private void vagrant(MoveContext context, Game game, Player currentPlayer) { - Card c = game.draw(currentPlayer); + Card c = game.draw(currentPlayer, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins())) { @@ -5448,7 +5442,7 @@ private void knight(MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = context.game.draw(targetPlayer); + Card card = context.game.draw(targetPlayer, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -5621,7 +5615,7 @@ private void soothsayer(Game game, MoveContext context, Player currentPlayer) if (curseGained.equals(Cards.curse)) { - drawToHand(game, player, this.controlCard); + game.drawToHand(player, this.controlCard, 1); } } } @@ -5728,7 +5722,7 @@ private void advisor(Game game, MoveContext context, Player currentPlayer) for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 3 - i); if (card != null) { @@ -5843,7 +5837,7 @@ private void journeyman(Game game, MoveContext context, Player currentPlayer) { int diffCardsFound = 0; // search for the first 3 cards that were not named - while (diffCardsFound < 3 && (last = context.game.draw(currentPlayer)) != null) { + while (diffCardsFound < 3 && (last = context.game.draw(currentPlayer, -1)) != null) { if (!last.equals(named)) { ++diffCardsFound; cardsToKeep.add(last); @@ -5949,7 +5943,7 @@ private void doctor(Game game, MoveContext context, Player currentPlayer) { ArrayList revealedCards = new ArrayList(); for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer); + Card card = game.draw(currentPlayer, 3 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -5976,7 +5970,7 @@ public void doctorOverpay(MoveContext context) { for (int i = 0; i < context.overpayAmount; ++i) { - Card card = context.game.draw(context.player); + Card card = context.game.draw(context.player, context.overpayAmount - i); if (card != null) { @@ -6002,7 +5996,7 @@ public void doctorOverpay(MoveContext context) private void herald(Game game, MoveContext context, Player currentPlayer) { - Card draw = game.draw(currentPlayer); + Card draw = game.draw(currentPlayer, 1); if (draw != null) { @@ -6191,7 +6185,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); - Card card = game.draw(targetPlayer); + Card card = game.draw(targetPlayer, 1); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); int cardCost = card.getCost(context); @@ -6237,7 +6231,7 @@ private void hero(Game game, MoveContext context, Player currentPlayer) private void magpie(Game game, MoveContext context, Player currentPlayer) { - Card c = game.draw(currentPlayer); + Card c = game.draw(currentPlayer , 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c instanceof TreasureCard) { @@ -6259,7 +6253,7 @@ private void messenger(Game game, MoveContext context, Player currentPlayer) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); } } } @@ -6312,13 +6306,13 @@ private void raze(Game game, MoveContext context, Player currentPlayer) { if (trashCost == 0) return; else if (trashCost == 1) { - Card c = game.draw(currentPlayer); + Card c = game.draw(currentPlayer, 1); if (c != null) currentPlayer.hand.add(c); } else { ArrayList lookAtCards = new ArrayList(trashCost); - while (lookAtCards.size() < trashCost) { - Card c = game.draw(currentPlayer); + for (int i = 0; i < trashCost; ++i) { + Card c = game.draw(currentPlayer, trashCost - i); if (c == null) break; lookAtCards.add(c); @@ -6366,7 +6360,7 @@ private void storyteller(Game game, MoveContext context, Player currentPlayer) { context.spendCoins(coins); for (int i = 0; i < coins; i++) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, coins - i); } } @@ -6389,7 +6383,7 @@ private void warrior(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card draw = game.draw(player); + Card draw = game.draw(player, numTravellers - i); if (draw != null) { int cost = draw.getCost(context); if (draw.costPotion()) diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 8649a820e..5e6fc3863 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -184,7 +184,7 @@ private void guide(MoveContext context, Game game, Player currentPlayer) { } } for (int i = 0; i < 5; ++i) { - game.drawToHand(currentPlayer, this.controlCard); + game.drawToHand(currentPlayer, this.controlCard, 5 - i); } } diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index f4db2f947..1b99d9ed3 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -338,7 +338,7 @@ private void save(MoveContext context) { private void scoutingParty(MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = context.game.draw(context.player); + Card card = context.game.draw(context.player, 5 - i); if (card != null) { cards.add(card); } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 7f3bd0c1e..57906e7a8 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -605,7 +605,7 @@ protected List playerEndTurn(Player player, MoveContext context) // draw next hand for (int i = 0; i < handCount; i++) { - drawToHand(player, null, false); + drawToHand(player, null, handCount - i, false); } if (player.save != null) { @@ -883,7 +883,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } else if(card.equals(Cards.horseTraders)) { Card horseTrader = player.horseTraders.remove(0); player.hand.add(horseTrader); - drawToHand(player, horseTrader); + drawToHand(player, horseTrader, 1); } else if(card instanceof DurationCard) { if(card.equals(Cards.haven) || card.equals(Cards.gear)) { player.hand.add(card2); @@ -914,7 +914,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } for (int i = 0; i < addCardsNextTurn; i++) { - drawToHand(player, thisCard, true); + drawToHand(player, thisCard, addCardsNextTurn - i, true); } if ( thisCard.getType() == Cards.Type.Amulet @@ -1649,17 +1649,17 @@ private boolean checkGameOver() { } // Use drawToHand when "drawing" or "+ X cards" when -1 Card token could be drawn instead - boolean drawToHand(Player player, Card responsible) { - return drawToHand(player, responsible, true); + boolean drawToHand(Player player, Card responsible, int cardsLeftToDraw) { + return drawToHand(player, responsible, cardsLeftToDraw, true); } - boolean drawToHand(Player player, Card responsible, boolean showUI) { + boolean drawToHand(Player player, Card responsible, int cardsLeftToDraw, boolean showUI) { if (player.getMinusOneCardToken()) { MoveContext context = new MoveContext(this, player); player.setMinusOneCardToken(false, context); return false; } - Card card = draw(player); + Card card = draw(player, cardsLeftToDraw); if (card == null) return false; @@ -1673,21 +1673,21 @@ boolean drawToHand(Player player, Card responsible, boolean showUI) { } // Use draw when removing a card from the top of the deck without "drawing" it (e.g. look at or reveal) - Card draw(Player player) { + Card draw(Player player, int cardsLeftToDraw) { if (player.deck.isEmpty()) { if (player.discard.isEmpty()) { return null; } else { - replenishDeck(player); + replenishDeck(player, cardsLeftToDraw); } } return player.deck.remove(0); } - public void replenishDeck(Player player) { + public void replenishDeck(Player player, int cardsLeftToDraw) { MoveContext context = new MoveContext(this, player); - player.replenishDeck(context); + player.replenishDeck(context, cardsLeftToDraw); GameEvent event = new GameEvent(GameEvent.Type.DeckReplenished, context); broadcastEvent(event); @@ -1925,7 +1925,7 @@ protected void initPlayerCards() { if (!equalStartHands || i == 0) { while (player.hand.size() < 5) - drawToHand(player, null, false); + drawToHand(player, null, 5 - player.hand.size(), false); } else { // make subsequent player hands equal @@ -1934,7 +1934,7 @@ protected void initPlayerCards() { player.discard.remove(card); player.hand.add(card); } - player.replenishDeck(null); + player.replenishDeck(null, 0); } } @@ -2686,7 +2686,7 @@ public void gameEvent(GameEvent event) { } else if(event.card.equals(Cards.lostCity)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { - drawToHand(targetPlayer, event.card, true); + drawToHand(targetPlayer, event.card, 1, true); } } } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index ae7bee909..6663c6bc7 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -826,13 +826,12 @@ public void putOnTopOfDeck(Card card) { deck.add(0, card); } - public void replenishDeck(MoveContext context) { + public void replenishDeck(MoveContext context, int cardsLeftToDraw) { shuffleCount++; - shuffleIntoDeck(context, discard); + shuffleIntoDeck(context, discard, cardsLeftToDraw); } - private void shuffleIntoDeck(MoveContext context, CardList source) { - int cardsLeftToDraw = 5; //TODO - dominionator - do this and don't forget to account for -1 card token + private void shuffleIntoDeck(MoveContext context, CardList source, int cardsLeftToDraw) { ArrayList stashes = new ArrayList(); int positionAll = -1; if (context != null) { @@ -846,7 +845,10 @@ private void shuffleIntoDeck(MoveContext context, CardList source) { if (source.size() == numStashes) { shuffleNormally = true; } else if (numStashes > 1) { - positionAll = this.controlPlayer.stash_chooseDeckPosition(context, source.size() - numStashes, numStashes, cardsLeftToDraw); + int afterCardsToDraw = cardsLeftToDraw; + if (afterCardsToDraw < 1) + afterCardsToDraw = source.size() - numStashes; + positionAll = this.controlPlayer.stash_chooseDeckPosition(context, source.size() - numStashes, numStashes, afterCardsToDraw); // -1 -> Pass (shuffle normally) // -2 or below -> (choose individually) if (positionAll > source.size() - numStashes) @@ -882,7 +884,11 @@ private void shuffleIntoDeck(MoveContext context, CardList source) { if (positionAll >= 0) { position = positionAll; } else { - position = controlPlayer.stash_chooseDeckPosition(context, deck.size(), 1, cardsLeftToDraw); + int afterCurrentCards = cardsLeftToDraw; + if (cardsLeftToDraw < 1) { + afterCurrentCards = deck.size(); + } + position = controlPlayer.stash_chooseDeckPosition(context, deck.size(), 1, afterCurrentCards); if (position < 0) position = Game.rand.nextInt(deck.size() + 1); position = Math.min(position, deck.size()); @@ -897,7 +903,7 @@ public void shuffleDeck(MoveContext context) { while (deck.size() > 0) { tempDeck.add(deck.remove(0)); } - shuffleIntoDeck(context, tempDeck); + shuffleIntoDeck(context, tempDeck, 0); } public void checkCardsValid() { diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 55b7edd5f..321ec09f3 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -180,7 +180,7 @@ protected boolean loanVenture(MoveContext context, Player player, Game game, boo GameEvent event = null; while (treasureCardFound == null) { - Card draw = game.draw(player); + Card draw = game.draw(player, -1); if (draw == null) { break; } diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 7b8985a3f..d668cebff 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -312,8 +312,8 @@ static boolean doSecretChamber(MoveContext context, Game game, Player player, Ca // event.card = Cards.secretChamber; // game.broadcastEvent(event); - game.drawToHand(player, responsible); - game.drawToHand(player, responsible); + game.drawToHand(player, responsible, 2); + game.drawToHand(player, responsible, 1); if (player.hand.size() > 0) { Card[] cards = player.controlPlayer.secretChamber_cardsToPutOnDeck(context); diff --git a/vdom/src/com/vdom/core/VictoryCardImpl.java b/vdom/src/com/vdom/core/VictoryCardImpl.java index 74641fe14..8329ca016 100644 --- a/vdom/src/com/vdom/core/VictoryCardImpl.java +++ b/vdom/src/com/vdom/core/VictoryCardImpl.java @@ -39,7 +39,7 @@ public void isTrashed(MoveContext context) switch (this.getType()) { case OvergrownEstate: - context.game.drawToHand(context.player, this); + context.game.drawToHand(context.player, this, 1); break; case Feodum: context.player.controlPlayer.gainNewCard(Cards.silver, this, context); From 08560d25deff36b3550138136f2183b6d2da3e5d Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 18 Jan 2016 23:11:21 -0700 Subject: [PATCH 041/141] Improved Stash reshuffle AI. AI will put Stash after cards to be drawn in certain cases e.g. when Vagrant requires reshuffle. Require MoveContext to perform reshuffle instead of Player since it can initate a player decision. --- .../com/mehtank/androminion/ui/Strings.java | 4 +- vdom/src/com/vdom/core/ActionCardImpl.java | 265 ++++++++++-------- vdom/src/com/vdom/core/BasePlayer.java | 19 +- .../com/vdom/core/CallableActionCardImpl.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/Game.java | 39 ++- vdom/src/com/vdom/core/IndirectPlayer.java | 33 ++- vdom/src/com/vdom/core/Player.java | 19 +- vdom/src/com/vdom/core/TreasureCardImpl.java | 3 +- vdom/src/com/vdom/core/Util.java | 4 +- vdom/src/com/vdom/core/VictoryCardImpl.java | 2 +- 11 files changed, 217 insertions(+), 175 deletions(-) diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 3f87c7178..02679771a 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -554,9 +554,9 @@ private static int getOptionStartIndex(Card card, Object[] options) { } else if (optionString.equals(IndirectPlayer.OPTION_START_TURN_EFFECT)) { return 1; } else if (optionString.equals(IndirectPlayer.OPTION_STASH)) { - return 4; + return 5; } else if (optionString.equals(IndirectPlayer.OPTION_STASH_POSITION)) { - return 3; + return 4; } } if (card == null) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 35f991083..b0b8151ea 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -249,7 +249,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCoin)) context.addCoins(1); if (game.isPlayerSupplyTokenOnPile(actualCard, currentPlayer, PlayerSupplyToken.PlusOneCard)) - game.drawToHand(currentPlayer, actualCard, 1 + addCards); + game.drawToHand(context, actualCard, 1 + addCards); context.actions += addActions; context.buys += addBuys; @@ -257,7 +257,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { currentPlayer.addVictoryTokens(context, addVictoryTokens); for (int i = 0; i < addCards; ++i) { - game.drawToHand(currentPlayer, this, addCards - i); + game.drawToHand(context, this, addCards - i); } additionalCardActions(game, context, currentPlayer); @@ -904,6 +904,7 @@ private void cutpurse(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; if (player.hand.contains(Cards.copper)) { Card card = player.hand.get(Cards.copper); @@ -989,7 +990,7 @@ private void embargo(Game game, MoveContext context, Player currentPlayer) { private void navigator(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = game.draw(currentPlayer, 5 - i); + Card card = game.draw(context, controlCard, 5 - i); if (card != null) { topOfTheDeck.add(card); } @@ -1042,7 +1043,7 @@ private void navigator(Game game, MoveContext context, Player currentPlayer) { private void lookout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer, 3 - i); + Card card = game.draw(context, controlCard, 3 - i); if (card != null) { cards.add(card); } @@ -1095,7 +1096,7 @@ private void lookout(Game game, MoveContext context, Player currentPlayer) { private void pearlDiver(MoveContext context, Player currentPlayer) { if (currentPlayer.getDeckSize() == 0 && currentPlayer.discard.size() > 0) { - context.game.replenishDeck(currentPlayer, 0); + context.game.replenishDeck(context, controlCard, 0); } if (currentPlayer.getDeckSize() > 1) { @@ -1248,7 +1249,7 @@ private void nativeVillage(Game game, MoveContext context, Player currentPlayer) currentPlayer.hand.add(currentPlayer.nativeVillage.remove(0)); } } else { - Card draw = game.draw(currentPlayer, 1); + Card draw = game.draw(context, controlCard, 1); if (draw != null) { currentPlayer.nativeVillage.add(draw); Util.sensitiveDebug(currentPlayer, "Added to Native Village:" + draw.getName(), true); @@ -1261,8 +1262,9 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; - Card draw = game.draw(player, 1); + Card draw = game.draw(playerContext, controlCard, 1); if (draw != null) { player.discard(draw, this.controlCard, playerContext); } @@ -1275,7 +1277,7 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { private void councilRoom(Game game, MoveContext context) { for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(new MoveContext(game, player), this.controlCard, 1); } } } @@ -1336,7 +1338,7 @@ private void apprentice(Game game, MoveContext context, Player currentPlayer) { int cardsToDraw = (cardToTrash.getCost(context) + (cardToTrash.costPotion() ? 2 : 0)); for (int i = 1; i <= cardsToDraw; i++) { - game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i); + game.drawToHand(context, this.controlCard, cardsToDraw - i); } } } @@ -1365,7 +1367,7 @@ private void transmute(MoveContext context, Player currentPlayer) { private void apothecary(Game game, MoveContext context, Player currentPlayer) { ArrayList residue = new ArrayList(); for (int i = 1; i <= 4; i++) { - Card card = game.draw(currentPlayer, 4 - i); + Card card = game.draw(context, controlCard, 4 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); if (card.equals(Cards.copper) || card.equals(Cards.potion)) { @@ -1392,7 +1394,9 @@ private void witchFamiliar(Game game, MoveContext context, Player currentPlayer) for (Player player : game.getPlayersInTurnOrder()) { if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); - player.gainNewCard(Cards.curse, this.controlCard, new MoveContext(game, player)); + MoveContext targetContext = new MoveContext(game, player); + targetContext.attackedPlayer = player; + player.gainNewCard(Cards.curse, this.controlCard, targetContext); } } } @@ -1479,7 +1483,7 @@ private void torturer(Game game, MoveContext context, Player currentPlayer) { private void scout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer, 4 - i); + Card card = game.draw(context, controlCard, 4 - i); if (card == null) { break; } @@ -1687,7 +1691,7 @@ private void bishop(Game game, MoveContext context, Player currentPlayer) { private void city(Game game, MoveContext context, Player currentPlayer) { if (game.emptyPiles() > 0) { - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 1); } if (game.emptyPiles() > 1) { context.buys++; @@ -1908,12 +1912,12 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - + playerContext.attackedPlayer = player; ArrayList topOfTheDeck = new ArrayList(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(player, 3 - i); + Card card = game.draw(playerContext, controlCard, 3 - i); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -2031,7 +2035,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { } if (numberOfCardsDiscarded == 2) { - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(playerContext, this.controlCard, 1); } } } @@ -2041,7 +2045,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { private void watchTower(Game game, MoveContext context, Player currentPlayer) { int cardsToDraw = 6 - currentPlayer.hand.size(); for (int i = 0; i < cardsToDraw; ++i) { - if(!game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i)) + if(!game.drawToHand(context, this.controlCard, cardsToDraw - i)) break; } } @@ -2051,7 +2055,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(currentPlayer, -1)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(context, controlCard, -1)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -2072,11 +2076,11 @@ private void fortuneTeller(Game game, MoveContext context, Player currentPlayer) if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); - + playerContext.attackedPlayer = player; ArrayList cardsToDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(player, -1)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { + while ((draw = game.draw(playerContext, controlCard, -1)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { player.reveal(draw, this.controlCard, playerContext); cardsToDiscard.add(draw); } @@ -2113,7 +2117,7 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { HashSet cardNames = new HashSet(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 4; i++) { - Card draw = game.draw(currentPlayer, 4 - i); + Card draw = game.draw(context, controlCard, 4 - i); if (draw == null) { break; } @@ -2162,16 +2166,17 @@ private void jester(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); + MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; - Card draw = game.draw(targetPlayer, 1); + Card draw = game.draw(targetContext, controlCard, 1); Card virtCard = draw; if (draw == null) { continue; } - - MoveContext targetContext = new MoveContext(game, targetPlayer); + targetPlayer.reveal(draw, this.controlCard, targetContext); targetPlayer.discard(draw, this.controlCard, targetContext); @@ -2214,7 +2219,7 @@ private void huntingParty(Game game, MoveContext context, Player currentPlayer) ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, -1)) != null && cardNames.contains(draw.getName())) { + while ((draw = game.draw(context, controlCard, -1)) != null && cardNames.contains(draw.getName())) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -2239,7 +2244,7 @@ private void crossroads(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < victoryCards; i++) { - game.drawToHand(currentPlayer, this.controlCard, victoryCards - i); + game.drawToHand(context, this.controlCard, victoryCards - i); } int crossroadsPlayed = this.controlCard.numberTimesAlreadyPlayed; @@ -2262,7 +2267,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { context.actions += 2; } else if (option == TrustySteedOption.AddCards) { for (int i = 0; i < 2; i++) { - game.drawToHand(currentPlayer, this.controlCard, 2 - i); + game.drawToHand(context, this.controlCard, 2 - i); } } else if (option == TrustySteedOption.AddGold) { context.addCoins(2); @@ -2285,9 +2290,9 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { private void duchess(Game game, MoveContext context) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - Card c = game.draw(targetPlayer, 1); + MoveContext targetPlayerContext = new MoveContext(context, game, targetPlayer); + Card c = game.draw(targetPlayerContext, controlCard, 1); if(c != null) { - MoveContext targetPlayerContext = new MoveContext(context, game, targetPlayer); boolean discard = (targetPlayer).controlPlayer.duchess_shouldDiscardCardFromTopOfDeck(targetPlayerContext, c); if(discard) { targetPlayer.discard(c, this.controlCard, targetPlayerContext); @@ -2319,8 +2324,8 @@ private void spiceMerchant(Game game, MoveContext context, Player currentPlayer) SpiceMerchantOption option = currentPlayer.controlPlayer.spiceMerchant_chooseOption(context); if(option == SpiceMerchantOption.AddCardsAndAction) { - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); context.actions += 1; } else { @@ -2354,7 +2359,7 @@ private void trader(MoveContext context, Player currentPlayer) { private void cartographer(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(currentPlayer, 4 - i); + Card card = game.draw(context, controlCard, 4 - i); if (card != null) { topOfTheDeck.add(card); } @@ -2533,8 +2538,8 @@ private void steward(Game game, MoveContext context, Player currentPlayer) { if (option == Player.StewardOption.AddGold) { context.addCoins(2); } else if (option == Player.StewardOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); } else if (option == Player.StewardOption.TrashCards) { CardList hand = currentPlayer.getHand(); if (hand.size() == 0) { @@ -2587,11 +2592,12 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; ArrayList treasures = new ArrayList(); List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, 2 - i); + Card card = game.draw(targetContext, controlCard, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -2753,7 +2759,7 @@ private void menagerie(Game game, MoveContext context, Player currentPlayer) { int numCards = distinct ? 3 : 1; for (int i = 0; i < numCards; i++) { - game.drawToHand(currentPlayer, this.controlCard, numCards - i); + game.drawToHand(context, this.controlCard, numCards - i); } } @@ -2807,7 +2813,7 @@ private void tournament(Game game, MoveContext context, Player currentPlayer) { } if (!opponentsRevealedProvince) { - game.drawToHand(currentPlayer, this, 1); + game.drawToHand(context, this, 1); context.addCoins(1); } } @@ -2946,14 +2952,15 @@ private void minion(Game game, MoveContext context, Player currentPlayer) { for (Player player : playersToAttack) { if (player == currentPlayer || player.hand.size() >= 5) { MoveContext targetContext = new MoveContext(game, player); + targetContext.attackedPlayer = player; while (!player.hand.isEmpty()) { player.discard(player.hand.remove(0), this.controlCard, targetContext); } - game.drawToHand(player, this.controlCard, 4); - game.drawToHand(player, this.controlCard, 3); - game.drawToHand(player, this.controlCard, 2); - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(targetContext, this.controlCard, 4); + game.drawToHand(targetContext, this.controlCard, 3); + game.drawToHand(targetContext, this.controlCard, 2); + game.drawToHand(targetContext, this.controlCard, 1); } } } @@ -2970,7 +2977,7 @@ private void pawn(Game game, MoveContext context, Player currentPlayer) { } else if (option == Player.PawnOption.AddBuy) { context.buys++; } else if (option == Player.PawnOption.AddCard) { - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 1); } else if (option == Player.PawnOption.AddGold) { context.addCoins(1); } @@ -2983,12 +2990,13 @@ private void saboteur(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; playerContext.cardCostModifier = context.cardCostModifier; ArrayList toDiscard = new ArrayList(); Card draw; - while ((draw = game.draw(player, -1)) != null) { + while ((draw = game.draw(playerContext, controlCard, -1)) != null) { if (draw.getCost(context) >= 3) { int value = draw.getCost(context); value -= 2; @@ -3037,8 +3045,8 @@ private void shantyTown(Game game, MoveContext context, Player currentPlayer) { } if (!actions) { - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); } } @@ -3086,7 +3094,8 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla } MoveContext playerContext = new MoveContext(game, player); - Card card = game.draw(player, 1); + playerContext.attackedPlayer = player; + Card card = game.draw(playerContext, controlCard, 1); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -3113,7 +3122,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla ArrayList cardsToPutInHand = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, -1)) != null) { + while ((draw = game.draw(context, controlCard, -1)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); if(!(draw instanceof ActionCard)) { @@ -3130,7 +3139,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla private void conspirator(Game game, MoveContext context, Player currentPlayer) { if (context.actionsPlayedSoFar >= 3) { context.actions++; - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 1); } } @@ -3146,7 +3155,7 @@ private void wishingWell(Game game, MoveContext context, Player currentPlayer) { if (!options.isEmpty()) { Card card = currentPlayer.controlPlayer.wishingWell_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(card, this.controlCard, context); - Card draw = game.draw(currentPlayer, 1); + Card draw = game.draw(context, controlCard, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -3197,7 +3206,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 1); } } } @@ -3211,9 +3220,9 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { if (option == Player.NoblesOption.AddActions) { context.actions += 2; } else if (option == Player.NoblesOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard, 3); - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 3); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); } } } @@ -3221,16 +3230,17 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { private void tribute(Game game, MoveContext context, Player currentPlayer) { Card[] revealedCards = new Card[2]; Player nextPlayer = game.getNextPlayer(); - revealedCards[0] = game.draw(nextPlayer, 2); - revealedCards[1] = game.draw(nextPlayer, 1); + MoveContext targetContext = new MoveContext(game, nextPlayer); + revealedCards[0] = game.draw(targetContext, controlCard, 2); + revealedCards[1] = game.draw(targetContext, controlCard, 1); if (revealedCards[0] != null) { - nextPlayer.reveal(revealedCards[0], this.controlCard, new MoveContext(game, nextPlayer)); + nextPlayer.reveal(revealedCards[0], this.controlCard, targetContext); (nextPlayer).discard(revealedCards[0], this.controlCard, null); } if (revealedCards[1] != null) { - nextPlayer.reveal(revealedCards[1], this.controlCard, new MoveContext(game, nextPlayer)); + nextPlayer.reveal(revealedCards[1], this.controlCard, targetContext); (nextPlayer).discard(revealedCards[1], this.controlCard, null); } @@ -3248,8 +3258,8 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { context.addCoins(2); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); } } } @@ -3264,8 +3274,9 @@ private void swindler(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; - Card draw = game.draw(player, 1); + Card draw = game.draw(playerContext, controlCard, 1); if (draw != null) { player.trash(draw, this.controlCard, playerContext); @@ -3363,7 +3374,9 @@ private void youngwitch(Game game, MoveContext context, Player currentPlayer) { targetPlayer.reveal(game.baneCard, this.controlCard, new MoveContext(game, targetPlayer)); } else { targetPlayer.attacked(this.controlCard, context); - targetPlayer.gainNewCard(Cards.curse, this.controlCard, new MoveContext(game, targetPlayer)); + MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; + targetPlayer.gainNewCard(Cards.curse, this.controlCard, targetContext); } } } @@ -3376,6 +3389,7 @@ private void followers(Game game, MoveContext context, Player currentPlayer) { if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; player.gainNewCard(Cards.curse, this.controlCard, playerContext); int keepCardCount = 3; @@ -3406,7 +3420,7 @@ private void stables(Game game, MoveContext context, Player currentPlayer) { context.actions++; for (int i = 0; i < 3; i++) { - if(!game.drawToHand(currentPlayer, this.controlCard, 3 - i)) { + if(!game.drawToHand(context, this.controlCard, 3 - i)) { break; } } @@ -3420,7 +3434,7 @@ private void margrave(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(playerContext, this.controlCard, 1); int keepCardCount = 3; if (player.hand.size() > keepCardCount) { @@ -3436,9 +3450,10 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { if (targetPlayer == currentPlayer || !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; ArrayList cards = new ArrayList(); for(int i=0; i < 2; i++) { - Card c = game.draw(targetPlayer, 2 - i); + Card c = game.draw(targetContext, controlCard, 2 - i); if(c == null) { break; } @@ -3487,7 +3502,7 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < 2; i++) { - game.drawToHand(currentPlayer, this.controlCard, 2 - i); + game.drawToHand(context, this.controlCard, 2 - i); } } @@ -3508,7 +3523,7 @@ private void oasis(MoveContext context, Player currentPlayer) { private void jackOfAllTrades(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); - Card c = game.draw(currentPlayer, 1); + Card c = game.draw(context, controlCard, 1); if(c != null) { boolean discard = currentPlayer.controlPlayer.jackOfAllTrades_shouldDiscardCardFromTopOfDeck(context, c); if(discard) { @@ -3520,7 +3535,7 @@ private void jackOfAllTrades(Game game, MoveContext context, Player currentPlaye int cardsToDraw = 5 - currentPlayer.hand.size(); for (int i = 0; i < cardsToDraw; ++i) { - if(!game.drawToHand(currentPlayer, this.controlCard, cardsToDraw - i)) { + if(!game.drawToHand(context, this.controlCard, cardsToDraw - i)) { break; } } @@ -3669,7 +3684,7 @@ private void cellar(Game game, MoveContext context, Player currentPlayer) { } for (int i = 0; i < numberOfCards; ++i) { - game.drawToHand(currentPlayer, this.controlCard, numberOfCards - i); + game.drawToHand(context, this.controlCard, numberOfCards - i); } } } @@ -3745,7 +3760,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { ArrayList toOrder = new ArrayList(); while (toOrder.size() < 2) { - Card draw = game.draw(currentPlayer, -1); + Card draw = game.draw(context, controlCard, -1); if (draw == null) { break; } @@ -3806,7 +3821,7 @@ private void adventurer(Game game, MoveContext context, Player currentPlayer) { int treasureCardsRevealed = 0; while (treasureCardsRevealed < 2) { - Card draw = game.draw(currentPlayer, -1); + Card draw = game.draw(context, controlCard, -1); if (draw == null) { break; } @@ -3831,7 +3846,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { // we need to manually remove the minus one card token currentPlayer.setMinusOneCardToken(false, context); while (currentPlayer.hand.size() < 7) { - Card draw = game.draw(currentPlayer, -1); + Card draw = game.draw(context, controlCard, -1); if (draw == null) { break; } @@ -3908,12 +3923,12 @@ private void pirateShip(Game game, MoveContext context, Player currentPlayer) { boolean treasureFound = false; for (Player targetPlayer : playersToAttack) { MoveContext targetContext = new MoveContext(game, targetPlayer); - + targetContext.attackedPlayer = targetPlayer; ArrayList treasures = new ArrayList(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, 2 - i); + Card card = game.draw(targetContext, controlCard, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4009,7 +4024,7 @@ private void chancellor(Game game, MoveContext context, Player currentPlayer) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); } } } @@ -4122,9 +4137,9 @@ protected CardList haven(Player player) { return player.haven; } - protected void drawToHand(Game game, Player player, Card responsible, int count) { + protected void drawToHand(MoveContext context, Card responsible, int count) { for (int i=0; i < count; i++) { - game.drawToHand(player, responsible, count - i); + context.game.drawToHand(context, responsible, count - i); } } @@ -4132,8 +4147,8 @@ protected void addToHand(Player player, Card card) { player.hand.add(card); } - protected Card draw(Game game, Player player, int cardsLeftToDraw) { - return game.draw(player, cardsLeftToDraw); + protected Card draw(MoveContext context, int cardsLeftToDraw) { + return context.game.draw(context, controlCard, cardsLeftToDraw); } protected Player[] getAllPlayers() { @@ -4219,12 +4234,13 @@ public void nobleBrigandAttack(MoveContext moveContext, boolean defensible) { if (targetPlayer != player && (!defensible || !Util.isDefendedFromAttack(context.game, targetPlayer, this.controlCard))) { targetPlayer.attacked(this.controlCard, moveContext); MoveContext targetContext = new MoveContext(context.game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; boolean treasureRevealed = false; ArrayList silverOrGold = new ArrayList(); List cardsToDiscard = new ArrayList(); for (int j = 0; j < 2; j++) { - Card card = context.game.draw(targetPlayer, 2 - j); + Card card = context.game.draw(targetContext, controlCard, 2 - j); if(card == null) { break; } @@ -4317,7 +4333,7 @@ private void sage(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(currentPlayer, -1)) != null && draw.getCost(context) < 3) { + while ((draw = game.draw(context, controlCard, -1)) != null && draw.getCost(context) < 3) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -4426,7 +4442,7 @@ public void beggar(Player currentPlayer, MoveContext context) { public void catacombs(Game game, Player currentPlayer, MoveContext context) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(currentPlayer, 3 - i); + Card card = game.draw(context, controlCard, 3 - i); if (card != null) { topOfTheDeck.add(card); } @@ -4437,9 +4453,9 @@ public void catacombs(Game game, Player currentPlayer, MoveContext context) { while (!topOfTheDeck.isEmpty()) { currentPlayer.discard(topOfTheDeck.remove(0), this.controlCard, context); } - game.drawToHand(currentPlayer, this.controlCard, 3); - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 3); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); } else { // Put the cards in hand for (Card c : topOfTheDeck) { @@ -4621,7 +4637,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { } private void ironmonger(Game game, Player currentPlayer, MoveContext context) { - Card card = game.draw(currentPlayer, 1); + Card card = game.draw(context, controlCard, 1); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -4638,7 +4654,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 1); } } } @@ -4667,7 +4683,7 @@ private void mystic(Game game, MoveContext context, Player currentPlayer) { if (options.size() > 0) { Card toName = currentPlayer.controlPlayer.mystic_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(toName, this.controlCard, context); - Card draw = game.draw(currentPlayer, 1); + Card draw = game.draw(context, controlCard, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -4693,7 +4709,7 @@ private void scavenger(Game game, MoveContext context, Player currentPlayer) game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); } } @@ -4733,7 +4749,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { } for (int i = 0; i < numberOfCards; ++i) { - game.drawToHand(currentPlayer, this.controlCard, numberOfCards - i); + game.drawToHand(context, this.controlCard, numberOfCards - i); } } @@ -4765,7 +4781,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { private void wanderingMinstrel(Player currentPlayer, MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = context.game.draw(currentPlayer, 3 - i); + Card card = context.game.draw(context, controlCard, 3 - i); if (card == null) { break; } @@ -4804,7 +4820,7 @@ private void rebuild(Player currentPlayer, MoveContext context) { Card last = null; // search for first Victory card that was not named - while ((last = context.game.draw(currentPlayer, -1)) != null) { + while ((last = context.game.draw(context, controlCard, -1)) != null) { if (last instanceof VictoryCard && !last.equals(named)) break; cards.add(last); currentPlayer.reveal(last, this.controlCard, context); @@ -4849,11 +4865,12 @@ private void rogue(Game game, MoveContext context, Player currentPlayer) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; ArrayList canTrash = new ArrayList(); List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetPlayer, 2 - i); + Card card = game.draw(targetContext, controlCard, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4941,12 +4958,12 @@ private void governor(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Governor option error, ignoring."); } else { if (option == Player.GovernorOption.AddCards) { - game.drawToHand(currentPlayer, this.controlCard, 3); - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 3); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(new MoveContext(game, player), this.controlCard, 1); } } } else if (option == Player.GovernorOption.GainTreasure) { @@ -5014,7 +5031,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); Player nextPlayer = game.getNextPlayer(); for (int i = 0; i < 5; i++) { - Card card = game.draw(currentPlayer, 5 - i); + Card card = game.draw(context, controlCard, 5 - i); if (card != null) { cards.add(card); currentPlayer.reveal(card, this.controlCard, context); @@ -5053,7 +5070,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { public void isTrashed(MoveContext context) { switch (this.controlCard.behaveAsCard().getType()) { case Rats: - context.game.drawToHand(context.player, this.controlCard, 1, true); + context.game.drawToHand(context, this.controlCard, 1, true); break; case Squire: // Need to ensure that there is at least one Attack card that can be gained, @@ -5126,9 +5143,9 @@ else if (gainEstates) context.player.hand.add(this.controlCard); break; case Cultist: - context.game.drawToHand(context.player, this.controlCard, 3, false); - context.game.drawToHand(context.player, this.controlCard, 2, false); - context.game.drawToHand(context.player, this.controlCard, 1, false); + context.game.drawToHand(context, this.controlCard, 3, false); + context.game.drawToHand(context, this.controlCard, 2, false); + context.game.drawToHand(context, this.controlCard, 1, false); break; case SirVander: context.player.controlPlayer.gainNewCard(Cards.gold, this.controlCard, context); @@ -5198,7 +5215,7 @@ public boolean isTraveller() { private void survivors(MoveContext context, Game game, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(currentPlayer, 2 - i); + Card card = game.draw(context, controlCard, 2 - i); if (card != null) { topOfTheDeck.add(card); } @@ -5253,6 +5270,7 @@ private void cultist(MoveContext context, Game game, Player currentPlayer) { if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; player.gainNewCard(Cards.virtualRuins, this.controlCard, playerContext); } } @@ -5314,8 +5332,8 @@ private void mercenary(MoveContext context, Game game, Player currentPlayer) if (cardsTrashedCount == 2) { - game.drawToHand(currentPlayer, this.controlCard, 2); - game.drawToHand(currentPlayer, this.controlCard, 1); + game.drawToHand(context, this.controlCard, 2); + game.drawToHand(context, this.controlCard, 1); context.addCoins(2); @@ -5345,6 +5363,7 @@ private void marauder(MoveContext context, Game game, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; player.gainNewCard(Cards.virtualRuins, this.controlCard, playerContext); } } @@ -5414,14 +5433,14 @@ private void madman(MoveContext context, Game game, Player currentPlayer) { int handSize = currentPlayer.hand.size(); for (int i = 0; i < handSize; ++i) { - game.drawToHand(currentPlayer, this.controlCard, handSize - i); + game.drawToHand(context, this.controlCard, handSize - i); } } } private void vagrant(MoveContext context, Game game, Player currentPlayer) { - Card c = game.draw(currentPlayer, 1); + Card c = game.draw(context, controlCard, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins())) { @@ -5442,7 +5461,7 @@ private void knight(MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = context.game.draw(targetPlayer, 2 - i); + Card card = context.game.draw(targetContext, controlCard, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -5610,12 +5629,13 @@ private void soothsayer(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; Card curseGained = player.gainNewCard(Cards.curse, this.controlCard, playerContext); if (curseGained.equals(Cards.curse)) { - game.drawToHand(player, this.controlCard, 1); + game.drawToHand(playerContext, this.controlCard, 1); } } } @@ -5641,6 +5661,7 @@ private void taxman(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); + playerContext.attackedPlayer = player; if (player.hand.size() >= 5) { @@ -5722,7 +5743,7 @@ private void advisor(Game game, MoveContext context, Player currentPlayer) for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer, 3 - i); + Card card = game.draw(context, controlCard, 3 - i); if (card != null) { @@ -5837,7 +5858,7 @@ private void journeyman(Game game, MoveContext context, Player currentPlayer) { int diffCardsFound = 0; // search for the first 3 cards that were not named - while (diffCardsFound < 3 && (last = context.game.draw(currentPlayer, -1)) != null) { + while (diffCardsFound < 3 && (last = context.game.draw(context, controlCard, -1)) != null) { if (!last.equals(named)) { ++diffCardsFound; cardsToKeep.add(last); @@ -5943,7 +5964,7 @@ private void doctor(Game game, MoveContext context, Player currentPlayer) { ArrayList revealedCards = new ArrayList(); for (int i = 0; i < 3; ++i) { - Card card = game.draw(currentPlayer, 3 - i); + Card card = game.draw(context, controlCard, 3 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -5970,7 +5991,7 @@ public void doctorOverpay(MoveContext context) { for (int i = 0; i < context.overpayAmount; ++i) { - Card card = context.game.draw(context.player, context.overpayAmount - i); + Card card = context.game.draw(context, controlCard, context.overpayAmount - i); if (card != null) { @@ -5996,7 +6017,7 @@ public void doctorOverpay(MoveContext context) private void herald(Game game, MoveContext context, Player currentPlayer) { - Card draw = game.draw(currentPlayer, 1); + Card draw = game.draw(context, controlCard, 1); if (draw != null) { @@ -6115,6 +6136,7 @@ private void bridgeTroll(Game game, MoveContext context, Player currentPlayer) for (Player targetPlayer : game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { MoveContext targetContext = new MoveContext(context.game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; targetPlayer.attacked(this.controlCard, context); targetPlayer.setMinusOneCoinToken(true, targetContext); } @@ -6184,8 +6206,9 @@ private void giant(Game game, MoveContext context, Player currentPlayer) for (Player targetPlayer : playersToAttack) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; - Card card = game.draw(targetPlayer, 1); + Card card = game.draw(targetContext, controlCard, 1); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); int cardCost = card.getCost(context); @@ -6231,7 +6254,7 @@ private void hero(Game game, MoveContext context, Player currentPlayer) private void magpie(Game game, MoveContext context, Player currentPlayer) { - Card c = game.draw(currentPlayer , 1); + Card c = game.draw(context, controlCard, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c instanceof TreasureCard) { @@ -6253,7 +6276,7 @@ private void messenger(Game game, MoveContext context, Player currentPlayer) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(currentPlayer, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); } } } @@ -6280,7 +6303,7 @@ private void miser(Game game, MoveContext context, Player currentPlayer) { private void ranger(Game game, MoveContext context, Player currentPlayer) { if(currentPlayer.flipJourneyToken(context)) { - drawToHand(game, currentPlayer, this.controlCard, 5); + drawToHand(context, this.controlCard, 5); } } @@ -6306,13 +6329,13 @@ private void raze(Game game, MoveContext context, Player currentPlayer) { if (trashCost == 0) return; else if (trashCost == 1) { - Card c = game.draw(currentPlayer, 1); + Card c = game.draw(context, controlCard, 1); if (c != null) currentPlayer.hand.add(c); } else { ArrayList lookAtCards = new ArrayList(trashCost); for (int i = 0; i < trashCost; ++i) { - Card c = game.draw(currentPlayer, trashCost - i); + Card c = game.draw(context, controlCard, trashCost - i); if (c == null) break; lookAtCards.add(c); @@ -6360,7 +6383,7 @@ private void storyteller(Game game, MoveContext context, Player currentPlayer) { context.spendCoins(coins); for (int i = 0; i < coins; i++) { - game.drawToHand(currentPlayer, this.controlCard, coins - i); + game.drawToHand(context, this.controlCard, coins - i); } } @@ -6383,7 +6406,7 @@ private void warrior(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card draw = game.draw(player, numTravellers - i); + Card draw = game.draw(playerContext, controlCard, numTravellers - i); if (draw != null) { int cost = draw.getCost(context); if (draw.costPotion()) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 97a29664c..bc6544593 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -967,6 +967,8 @@ public Card[] tradingPost_cardsToTrash(MoveContext context) { @Override public Card wishingWell_cardGuess(MoveContext context, ArrayList cardList) { + if (context.getPlayer().isStashOnDeck()) + return Cards.stash; return Cards.silver; } @@ -2463,6 +2465,8 @@ public boolean marketSquare_shouldDiscard(MoveContext context) { @Override public Card mystic_cardGuess(MoveContext context, ArrayList cardList) { + if (context.getPlayer().isStashOnDeck()) + return Cards.stash; return Cards.silver; } @@ -2698,9 +2702,20 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { } @Override - public int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw) { - if (context.attackedPlayer == this) + public int stash_chooseDeckPosition(MoveContext context, Card responsible, int deckSize, int numStashes, int cardsToDraw) { + if (context.attackedPlayer == this && !Cards.margrave.equals(responsible.behaveAsCard()) + && !Cards.soothsayer.equals(responsible.behaveAsCard())) return cardsToDraw; + if (Cards.vagrant.equals(responsible.behaveAsCard()) + || Cards.doctor.equals(responsible.behaveAsCard()) + || Cards.herald.equals(responsible.behaveAsCard()) + || Cards.envoy.equals(responsible.behaveAsCard()) + || Cards.advisor.equals(responsible.behaveAsCard()) + || Cards.secretChamber.equals(responsible.behaveAsCard()) + || Cards.tribute.equals(responsible.behaveAsCard())) { + return cardsToDraw; + } + return 0; } diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 5e6fc3863..643af2645 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -184,7 +184,7 @@ private void guide(MoveContext context, Game game, Player currentPlayer) { } } for (int i = 0; i < 5; ++i) { - game.drawToHand(currentPlayer, this.controlCard, 5 - i); + game.drawToHand(context, this.controlCard, 5 - i); } } diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 1b99d9ed3..7dea27a4f 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -338,7 +338,7 @@ private void save(MoveContext context) { private void scoutingParty(MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = context.game.draw(context.player, 5 - i); + Card card = context.game.draw(context, controlCard, 5 - i); if (card != null) { cards.add(card); } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 57906e7a8..343597dc9 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -605,7 +605,7 @@ protected List playerEndTurn(Player player, MoveContext context) // draw next hand for (int i = 0; i < handCount; i++) { - drawToHand(player, null, handCount - i, false); + drawToHand(context, null, handCount - i, false); } if (player.save != null) { @@ -883,7 +883,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } else if(card.equals(Cards.horseTraders)) { Card horseTrader = player.horseTraders.remove(0); player.hand.add(horseTrader); - drawToHand(player, horseTrader, 1); + drawToHand(context, horseTrader, 1); } else if(card instanceof DurationCard) { if(card.equals(Cards.haven) || card.equals(Cards.gear)) { player.hand.add(card2); @@ -914,7 +914,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } for (int i = 0; i < addCardsNextTurn; i++) { - drawToHand(player, thisCard, addCardsNextTurn - i, true); + drawToHand(context, thisCard, addCardsNextTurn - i, true); } if ( thisCard.getType() == Cards.Type.Amulet @@ -1649,17 +1649,17 @@ private boolean checkGameOver() { } // Use drawToHand when "drawing" or "+ X cards" when -1 Card token could be drawn instead - boolean drawToHand(Player player, Card responsible, int cardsLeftToDraw) { - return drawToHand(player, responsible, cardsLeftToDraw, true); + boolean drawToHand(MoveContext context, Card responsible, int cardsLeftToDraw) { + return drawToHand(context, responsible, cardsLeftToDraw, true); } - boolean drawToHand(Player player, Card responsible, int cardsLeftToDraw, boolean showUI) { + boolean drawToHand(MoveContext context, Card responsible, int cardsLeftToDraw, boolean showUI) { + Player player = context.player; if (player.getMinusOneCardToken()) { - MoveContext context = new MoveContext(this, player); player.setMinusOneCardToken(false, context); return false; } - Card card = draw(player, cardsLeftToDraw); + Card card = draw(context, responsible, cardsLeftToDraw); if (card == null) return false; @@ -1673,21 +1673,20 @@ boolean drawToHand(Player player, Card responsible, int cardsLeftToDraw, boolean } // Use draw when removing a card from the top of the deck without "drawing" it (e.g. look at or reveal) - Card draw(Player player, int cardsLeftToDraw) { - if (player.deck.isEmpty()) { - if (player.discard.isEmpty()) { + Card draw(MoveContext context, Card responsible, int cardsLeftToDraw) { + if (context.player.deck.isEmpty()) { + if (context.player.discard.isEmpty()) { return null; } else { - replenishDeck(player, cardsLeftToDraw); + replenishDeck(context, responsible, cardsLeftToDraw); } } - return player.deck.remove(0); + return context.player.deck.remove(0); } - public void replenishDeck(Player player, int cardsLeftToDraw) { - MoveContext context = new MoveContext(this, player); - player.replenishDeck(context, cardsLeftToDraw); + public void replenishDeck(MoveContext context, Card responsible, int cardsLeftToDraw) { + context.player.replenishDeck(context, responsible, cardsLeftToDraw); GameEvent event = new GameEvent(GameEvent.Type.DeckReplenished, context); broadcastEvent(event); @@ -1925,7 +1924,7 @@ protected void initPlayerCards() { if (!equalStartHands || i == 0) { while (player.hand.size() < 5) - drawToHand(player, null, 5 - player.hand.size(), false); + drawToHand(new MoveContext(this, player), null, 5 - player.hand.size(), false); } else { // make subsequent player hands equal @@ -1934,7 +1933,7 @@ protected void initPlayerCards() { player.discard.remove(card); player.hand.add(card); } - player.replenishDeck(null, 0); + player.replenishDeck(null, null, 0); } } @@ -2634,7 +2633,7 @@ public void gameEvent(GameEvent event) { player.discard.remove(c); player.deck.add(c); } - player.shuffleDeck(context); + player.shuffleDeck(context, event.card); } } else if (event.card.equals(Cards.borderVillage)) { boolean validCard = false; @@ -2686,7 +2685,7 @@ public void gameEvent(GameEvent event) { } else if(event.card.equals(Cards.lostCity)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { - drawToHand(targetPlayer, event.card, 1, true); + drawToHand(new MoveContext(Game.this, targetPlayer), event.card, 1, true); } } } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 5652311b6..d0a835d01 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2245,21 +2245,22 @@ public enum StashOption { } @Override - public int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw) { + public int stash_chooseDeckPosition(MoveContext context, Card responsible, int deckSize, int numStashes, int cardsToDraw) { if(context.isQuickPlay() && shouldAutoPlay_stash_chooseDeckPosition(context, deckSize, numStashes, cardsToDraw)) { - return super.stash_chooseDeckPosition(context, deckSize, numStashes, cardsToDraw); + return super.stash_chooseDeckPosition(context, responsible, deckSize, numStashes, cardsToDraw); } // Simple options first - Object[] options = new Object[7]; + Object[] options = new Object[8]; options[0] = OPTION_STASH; options[1] = deckSize; options[2] = numStashes; options[3] = cardsToDraw; - options[4] = StashOption.PlaceOnTop; - options[5] = StashOption.PlaceAfterCardsToDraw; - options[6] = StashOption.PlaceOther; + options[4] = responsible != null ? responsible.behaveAsCard() : null; + options[5] = StashOption.PlaceOnTop; + options[6] = StashOption.PlaceAfterCardsToDraw; + options[7] = StashOption.PlaceOther; - StashOption option = (StashOption) options[selectOption(context, Cards.stash, options) + 4]; + StashOption option = (StashOption) options[selectOption(context, Cards.stash, options) + 5]; if (option == StashOption.PlaceOnTop) { return 0; } else if (option == StashOption.PlaceAfterCardsToDraw) { @@ -2269,24 +2270,26 @@ public int stash_chooseDeckPosition(MoveContext context, int deckSize, int numSt } // advanced options if player chose other if (numStashes > 1) { - options = new Object[deckSize + 6]; + options = new Object[deckSize + 7]; options[0] = OPTION_STASH_POSITION; options[1] = deckSize; options[2] = numStashes; - for (int i = 3; i < options.length; ++i) { - options[i] = i - 5; + options[3] = responsible != null ? responsible.behaveAsCard() : null; + for (int i = 4; i < options.length; ++i) { + options[i] = i - 6; } - return (Integer) options[selectOption(context, Cards.stash, options) + 3]; + return (Integer) options[selectOption(context, Cards.stash, options) + 4]; } - options = new Object[deckSize + 5]; + options = new Object[deckSize + 6]; options[0] = OPTION_STASH_POSITION; options[1] = deckSize; options[2] = numStashes; - for (int i = 3; i < options.length; ++i) { - options[i] = i - 4; + options[3] = responsible != null ? responsible.behaveAsCard() : null; + for (int i = 4; i < options.length; ++i) { + options[i] = i - 5; } - return (Integer) options[selectOption(context, Cards.stash, options) + 3]; + return (Integer) options[selectOption(context, Cards.stash, options) + 4]; } @Override diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 6663c6bc7..2f04b7d8b 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -826,12 +826,12 @@ public void putOnTopOfDeck(Card card) { deck.add(0, card); } - public void replenishDeck(MoveContext context, int cardsLeftToDraw) { + public void replenishDeck(MoveContext context, Card responsible, int cardsLeftToDraw) { shuffleCount++; - shuffleIntoDeck(context, discard, cardsLeftToDraw); + shuffleIntoDeck(context, responsible, discard, cardsLeftToDraw); } - private void shuffleIntoDeck(MoveContext context, CardList source, int cardsLeftToDraw) { + private void shuffleIntoDeck(MoveContext context, Card responsible, CardList source, int cardsLeftToDraw) { ArrayList stashes = new ArrayList(); int positionAll = -1; if (context != null) { @@ -848,11 +848,11 @@ private void shuffleIntoDeck(MoveContext context, CardList source, int cardsLeft int afterCardsToDraw = cardsLeftToDraw; if (afterCardsToDraw < 1) afterCardsToDraw = source.size() - numStashes; - positionAll = this.controlPlayer.stash_chooseDeckPosition(context, source.size() - numStashes, numStashes, afterCardsToDraw); + positionAll = this.controlPlayer.stash_chooseDeckPosition(context, responsible, source.size() - numStashes, numStashes, afterCardsToDraw); // -1 -> Pass (shuffle normally) // -2 or below -> (choose individually) if (positionAll > source.size() - numStashes) - positionAll = -1; + positionAll = source.size() - numStashes; if (positionAll == -1) { shuffleNormally = true; } @@ -883,12 +883,13 @@ private void shuffleIntoDeck(MoveContext context, CardList source, int cardsLeft int position; if (positionAll >= 0) { position = positionAll; + position = Math.min(position, deck.size()); } else { int afterCurrentCards = cardsLeftToDraw; if (cardsLeftToDraw < 1) { afterCurrentCards = deck.size(); } - position = controlPlayer.stash_chooseDeckPosition(context, deck.size(), 1, afterCurrentCards); + position = controlPlayer.stash_chooseDeckPosition(context, responsible, deck.size(), 1, afterCurrentCards); if (position < 0) position = Game.rand.nextInt(deck.size() + 1); position = Math.min(position, deck.size()); @@ -898,12 +899,12 @@ private void shuffleIntoDeck(MoveContext context, CardList source, int cardsLeft } } - public void shuffleDeck(MoveContext context) { + public void shuffleDeck(MoveContext context, Card responsible) { CardList tempDeck = new CardList(this, name); while (deck.size() > 0) { tempDeck.add(deck.remove(0)); } - shuffleIntoDeck(context, tempDeck, 0); + shuffleIntoDeck(context, responsible, tempDeck, 0); } public void checkCardsValid() { @@ -1844,7 +1845,7 @@ public ArrayList getActionsInHand() { public abstract Card envoy_cardToDiscard(MoveContext context, Card[] revealedCards); - public abstract int stash_chooseDeckPosition(MoveContext context, int deckSize, int numStashes, int cardsToDraw); + public abstract int stash_chooseDeckPosition(MoveContext context, Card responsible, int deckSize, int numStashes, int cardsToDraw); public abstract boolean survivors_shouldDiscardTopCards(MoveContext context, Card[] array); diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 321ec09f3..7212a70e4 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -180,7 +180,7 @@ protected boolean loanVenture(MoveContext context, Player player, Game game, boo GameEvent event = null; while (treasureCardFound == null) { - Card draw = game.draw(player, -1); + Card draw = game.draw(context, controlCard, -1); if (draw == null) { break; } @@ -326,6 +326,7 @@ protected void relic(MoveContext context, Player player, Game game) { for (Player targetPlayer : playersToAttack) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(context.game, targetPlayer); + targetContext.attackedPlayer = targetPlayer; targetPlayer.setMinusOneCardToken(true, targetContext); } } diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index d668cebff..3cc13552d 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -312,8 +312,8 @@ static boolean doSecretChamber(MoveContext context, Game game, Player player, Ca // event.card = Cards.secretChamber; // game.broadcastEvent(event); - game.drawToHand(player, responsible, 2); - game.drawToHand(player, responsible, 1); + game.drawToHand(context, Cards.secretChamber, 2); + game.drawToHand(context, Cards.secretChamber, 1); if (player.hand.size() > 0) { Card[] cards = player.controlPlayer.secretChamber_cardsToPutOnDeck(context); diff --git a/vdom/src/com/vdom/core/VictoryCardImpl.java b/vdom/src/com/vdom/core/VictoryCardImpl.java index 8329ca016..bb0767fb2 100644 --- a/vdom/src/com/vdom/core/VictoryCardImpl.java +++ b/vdom/src/com/vdom/core/VictoryCardImpl.java @@ -39,7 +39,7 @@ public void isTrashed(MoveContext context) switch (this.getType()) { case OvergrownEstate: - context.game.drawToHand(context.player, this, 1); + context.game.drawToHand(context, controlCard, 1); break; case Feodum: context.player.controlPlayer.gainNewCard(Cards.silver, this, context); From 7f3474d797e96df5874cf4961854cb3cc3936215 Mon Sep 17 00:00:00 2001 From: dominionator Date: Tue, 19 Jan 2016 00:27:17 -0700 Subject: [PATCH 042/141] Random Alchemy games use recommended card numbers. If at least one Alchemy card is in a Random Kingdom, but less than the recommended number (3 to 5), then cards are replaced at random to equal one of the recommended numbers. This results in higher numbers of all cards random Kingdoms with lots of Alchemy cards (~39%), but they should be more balanced. --- vdom/src/com/vdom/core/CardSet.java | 54 +++++++++++++++++++++++++---- vdom/src/com/vdom/core/Game.java | 2 +- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/vdom/src/com/vdom/core/CardSet.java b/vdom/src/com/vdom/core/CardSet.java index 0a8319191..68eee7b88 100644 --- a/vdom/src/com/vdom/core/CardSet.java +++ b/vdom/src/com/vdom/core/CardSet.java @@ -46,10 +46,10 @@ private CardSet(final List cards, final boolean isRandom) { } public static CardSet getCardSet(final GameType type, int count) { - return getCardSet(type, count, null, false, -1); + return getCardSet(type, count, null, false, -1, false); } - public static CardSet getCardSet(final GameType type, int count, List randomExpansions, boolean randomIncludeEvents, int numRandomEvents) { + public static CardSet getCardSet(final GameType type, int count, List randomExpansions, boolean randomIncludeEvents, int numRandomEvents, boolean adjustRandomForAlchemy) { CardSet set = CardSet.CardSetMap.get(type); if(set == null) { @@ -69,18 +69,18 @@ public static CardSet getCardSet(final GameType type, int count, List if (randomIncludeEvents) { cards.addAll(Cards.eventsCards); } - set = CardSet.getRandomCardSet(cards, count, numRandomEvents); + set = CardSet.getRandomCardSet(cards, count, numRandomEvents, adjustRandomForAlchemy); } return set; } public static CardSet getRandomCardSet(final List possibleCards) { - return getRandomCardSet(possibleCards, -1, 0); + return getRandomCardSet(possibleCards, -1, 0, false); } public static CardSet getRandomCardSet(final List possibleCards, int count) { - return getRandomCardSet(possibleCards, count, 0); + return getRandomCardSet(possibleCards, count, 0, false); } /** @@ -93,7 +93,7 @@ public static CardSet getRandomCardSet(final List possibleCards, int count * at most that absolute value of Events using the selection method suggested in the rules * @return A random CardSet selected from the list of entered cards */ - public static CardSet getRandomCardSet(List possibleCards, int count, int eventCount) { + public static CardSet getRandomCardSet(List possibleCards, int count, int eventCount, boolean adjustForAlchemy) { final List cardSetList = new ArrayList(); final List eventList = new ArrayList(); @@ -155,11 +155,51 @@ public static CardSet getRandomCardSet(List possibleCards, int count, int } } + // Do Alchemy recommendation - if at least one Alchemy card is in, use 3 to 5 at once + if (adjustForAlchemy) + performAlchemyRecommendation(cardSetList, possibleCards); + cardSetList.addAll(eventList); return new CardSet(cardSetList, baneCard); } + private static int MIN_RECOMMENDED_ALCHEMY = 3; + private static int MAX_RECOMMENDED_ALCHEMY = 5; + private static void performAlchemyRecommendation(List cardSetList, List possibleCards) { + if (cardSetList.size() < MIN_RECOMMENDED_ALCHEMY) + return; + + Set alchemyCardsUsed = new HashSet(); + for (Card c : cardSetList) { + if (c.getExpansion().equals("Alchemy")) + alchemyCardsUsed.add(c); + } + + int numAlchemyCards = alchemyCardsUsed.size(); + if (!(numAlchemyCards > 0 && numAlchemyCards < MIN_RECOMMENDED_ALCHEMY)) + return; + + int numAlchemyCardsToUse = rand.nextInt(MAX_RECOMMENDED_ALCHEMY - MIN_RECOMMENDED_ALCHEMY + 1) + MIN_RECOMMENDED_ALCHEMY; + numAlchemyCardsToUse = Math.min(numAlchemyCardsToUse, Expansion.Alchemy.getKingdomCards().size() - numAlchemyCards); + + LinkedList cardsToPickFrom = new LinkedList(); + for (Card c : Expansion.Alchemy.getKingdomCards()) { + if (!alchemyCardsUsed.contains(c)) + cardsToPickFrom.add(c); + } + + for(int i = 0; i < cardSetList.size(); ++i) { + if (alchemyCardsUsed.contains(cardSetList.get(i))) + continue; + Card replacement = cardsToPickFrom.remove(rand.nextInt(cardsToPickFrom.size())); + cardSetList.set(i, replacement); + numAlchemyCards++; + if (numAlchemyCards == numAlchemyCardsToUse) + break; + } + } + private static Card swapOutBaneCard(List swapFrom, List replaceFrom) { Card bane = null; for (Card c : swapFrom) { @@ -323,7 +363,7 @@ public boolean isRandom() { CardSetMap.put(GameType.DecisionsDecisions, new CardSet(new Card[]{Cards.merchantGuild, Cards.candlestickMaker, Cards.masterpiece, Cards.taxman, Cards.butcher, Cards.bridge, Cards.pawn, Cards.miningVillage, Cards.upgrade, Cards.duke}, null)); /*frr18 AdventureTest*/ - CardSetMap.put(GameType.AdventureTest, new CardSet(new Card[]{Cards.ratcatcher, Cards.quest, Cards.miser, Cards.guide, Cards.transmogrify, Cards.wineMerchant, Cards.chapel, Cards.throneRoom, Cards.contraband, Cards.peasant, Cards.embargo, Cards.mission, Cards.hireling, Cards.seaway}, null)); + CardSetMap.put(GameType.AdventureTest, new CardSet(new Card[]{Cards.library, Cards.inn, Cards.transmogrify, Cards.stash, Cards.chapel, Cards.throneRoom, Cards.contraband, Cards.workersVillage, Cards.embargo, Cards.apprentice, Cards.borrow, Cards.lostArts, Cards.pathfinding}, null)); CardSetMap.put(GameType.GentleIntro, new CardSet(new Card[] { Cards.amulet, Cards.distantLands, Cards.dungeon, Cards.duplicate, Cards.giant, Cards.hireling, Cards.port, Cards.ranger, Cards.ratcatcher, Cards.treasureTrove, Cards.scoutingParty}, null)); CardSetMap.put(GameType.ExpertIntro, new CardSet(new Card[] { Cards.caravanGuard, Cards.coinOfTheRealm, Cards.hauntedWoods, Cards.lostCity, Cards.magpie, Cards.peasant, Cards.raze, Cards.swampHag, Cards.transmogrify, Cards.wineMerchant, Cards.mission, Cards.plan}, null)); CardSetMap.put(GameType.LevelUp, new CardSet(new Card[] { Cards.dungeon, Cards.gear, Cards.guide, Cards.lostCity, Cards.miser, Cards.market, Cards.militia, Cards.spy, Cards.throneRoom, Cards.workshop, Cards.training}, null)); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 343597dc9..3f51cf2f0 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -2130,7 +2130,7 @@ protected void initCards() { gameType = GameType.Specified; } else { - CardSet cardSet = CardSet.getCardSet(gameType, -1, randomExpansions, randomIncludesEvents, numRandomEvents); + CardSet cardSet = CardSet.getCardSet(gameType, -1, randomExpansions, randomIncludesEvents, numRandomEvents, true); if(cardSet == null) { cardSet = CardSet.getCardSet(CardSet.defaultGameType, -1); } From 128a406252a0f61186c29e0a8c8a704b5a0bb1f7 Mon Sep 17 00:00:00 2001 From: dominionator Date: Tue, 19 Jan 2016 01:26:22 -0700 Subject: [PATCH 043/141] Adding Bane card message to long press card view. Fixing bug where event card could be chosen as Bane card. Fixing issue with Treasure Map in preparation for Inheritance. --- androminion/res/values/strings-ui.xml | 1 + .../com/mehtank/androminion/ui/CardView.java | 19 ++++++++++++------- vdom/src/com/vdom/core/ActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardSet.java | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/androminion/res/values/strings-ui.xml b/androminion/res/values/strings-ui.xml index c2fce919e..25abc979b 100644 --- a/androminion/res/values/strings-ui.xml +++ b/androminion/res/values/strings-ui.xml @@ -189,4 +189,5 @@ :\u0020 ,\u0020 Embargoes + Bane card diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index d219dba8b..68ac6fb7b 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -581,14 +581,14 @@ public boolean onLongClick(View view) { im.setImageURI(u); im.setScaleType(ImageView.ScaleType.FIT_CENTER); - String tokenDesc = getTokenDescription(); - if (!tokenDesc.isEmpty()) { + String extraDesc = getExtraDescription(); + if (!extraDesc.isEmpty()) { LinearLayout ll = new LinearLayout(view.getContext()); ll.setOrientation(LinearLayout.VERTICAL); ll.addView(im); TextView textView = new TextView(view.getContext()); textView.setPadding(15, 0, 15, 5); - textView.setText(tokenDesc); + textView.setText(extraDesc); ll.addView(textView); v = ll; } else { @@ -609,9 +609,9 @@ public boolean onLongClick(View view) { text += "\n"; text += cardView.getCard().desc; - String tokenDescription = getTokenDescription(); - if (!tokenDescription.isEmpty()) { - text += "\n\n" + tokenDescription; + String extraDescription = getExtraDescription(); + if (!extraDescription.isEmpty()) { + text += "\n\n" + extraDescription; } textView.setText( text ); @@ -634,10 +634,15 @@ public boolean onLongClick(View view) { return true; } - private String getTokenDescription() { + private String getExtraDescription() { String text = ""; + if (state.c.isBane) { + text += getContext().getString(R.string.bane_card); + } boolean hasPlayerTokens = players != null && currentTokens != null && countTokens(currentTokens) > 0; if (hasPlayerTokens || numEmbargos > 0) { + if (text.length() > 0) + text += "\n\n"; text += getContext().getString(R.string.token_header); text += "\n"; if (numEmbargos > 0) { diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index b0b8151ea..598503598 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -943,7 +943,7 @@ private void treasureMap(MoveContext context, Player currentPlayer) { // Check for Treasure Map in hand Card anotherMap = null; for (Card card : currentPlayer.hand) { - if (card.equals(this)) { + if (card.equals(Cards.treasureMap)) { anotherMap = card; break; } diff --git a/vdom/src/com/vdom/core/CardSet.java b/vdom/src/com/vdom/core/CardSet.java index 68eee7b88..b8fe98b94 100644 --- a/vdom/src/com/vdom/core/CardSet.java +++ b/vdom/src/com/vdom/core/CardSet.java @@ -224,7 +224,7 @@ private static Card swapOutBaneCard(List swapFrom, List replaceFrom) private static boolean isValidBane(Card c) { int cost = c.getCost(null); - return !c.costPotion() && (cost == 2 || cost == 3); + return !c.costPotion() && (cost == 2 || cost == 3) && !c.isEvent(); } private static void pick(List source, List target, int count) { From fbe6117c310860714e86ad71aede089559c6b9e8 Mon Sep 17 00:00:00 2001 From: dominionator Date: Tue, 19 Jan 2016 02:40:04 -0700 Subject: [PATCH 044/141] Fixed download images of basic supply cards. --- androminion/src/com/mehtank/androminion/ui/CardView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/androminion/src/com/mehtank/androminion/ui/CardView.java b/androminion/src/com/mehtank/androminion/ui/CardView.java index 68ac6fb7b..fc1ffba3b 100644 --- a/androminion/src/com/mehtank/androminion/ui/CardView.java +++ b/androminion/src/com/mehtank/androminion/ui/CardView.java @@ -546,6 +546,14 @@ public boolean onLongClick(View view) { st = new StringTokenizer(str," ",false); String exp = ""; while (st.hasMoreElements()) exp += st.nextElement(); + if (exp.length() == 0) + exp = "common"; + if (filename.equals("potion")) + exp = "alchemy"; + else if (filename.equals("colony")) + exp = "prosperity"; + else if (filename.equals("platinum")) + exp = "prosperity"; View v; From 98c2b9ae8c16592b5b1fa528eee433185dc52c6b Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 20 Jan 2016 02:19:54 -0700 Subject: [PATCH 045/141] Summon Promo card. Missing a few issues with lose track rule, e.g. gained Inn when not taken out of discard for shuffling into deck. Fixing Inn's when-gain ability to always shuffle deck (matters for Stash). --- androminion/res/values/strings-server.xml | 3 +- .../com/mehtank/androminion/ui/Strings.java | 9 ++++-- vdom/src/com/vdom/api/GameEvent.java | 1 + vdom/src/com/vdom/core/BasePlayer.java | 5 +++ vdom/src/com/vdom/core/EventCardImpl.java | 12 +++++++ vdom/src/com/vdom/core/Game.java | 32 +++++++++++++++++-- vdom/src/com/vdom/core/IndirectPlayer.java | 10 ++++++ vdom/src/com/vdom/core/Player.java | 10 ++++++ vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 +++ vdom/src/com/vdom/core/Util.java | 2 +- 10 files changed, 82 insertions(+), 6 deletions(-) diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 48ece35d4..230a6c6ff 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -149,7 +149,8 @@ Card put on tavern mat Calling Called - Card set aside (prince) + Card set aside (Prince) + Card set aside (Summon) Card set aside (Haven) Card set aside (Gear) Card set aside (Save) diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index 02679771a..a9be275f0 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -276,6 +276,8 @@ public static String getStatusText(Event event, Object[] extras) { statusText += getString(R.string.PlayingDurationAction); } else if (event.gameEventType == GameEvent.Type.CardSetAside) { statusText += getString(R.string.CardSetAside); + } else if (event.gameEventType == GameEvent.Type.CardSetAsideSummon) { + statusText += getString(R.string.CardSetAsideSummon); } else if (event.gameEventType == GameEvent.Type.CardSetAsideHaven) { statusText += getString(R.string.CardSetAsideHaven); } else if (event.gameEventType == GameEvent.Type.CardSetAsideGear) { @@ -489,7 +491,8 @@ public static String[] getOptions(Card card, Object[] options) { || ((Card)options[i]).equals(Cards.gear) ) { strings2[(i - startIndex)/2] = getCardName((Card)options[i]) + " (" + "\u261e" + getCardName(((Card) options[i+1])) + ")"; - } else if(((Card)options[i]).equals(Cards.prince)) { + } else if(((Card)options[i]).equals(Cards.prince) + || ((Card)options[i]).equals(Cards.summon)) { strings2[(i - startIndex)/2] = getCardName((Card)options[i+1]) + " (" + getCardName(((Card) options[i])) + ")"; } else if(((Card)options[i]).equals(Cards.horseTraders)) { @@ -1302,7 +1305,9 @@ private static void initActionStrings() { getCardName(Cards.alms), getCardName(Cards.ball), getCardName(Cards.pilgrimage), - getCardName(Cards.seaway) + getCardName(Cards.seaway), + /*Promo Events*/ + getCardName(Cards.summon) )); actionStringMap = new HashMap(); diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index 66a727ed5..d699eb6ff 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -40,6 +40,7 @@ public enum Type { CardAddedToHand, // A new card has been added to a player's hand CardRemovedFromHand, // A card has been removed from a player's hand CardSetAside, // A card was set aside (prince) + CardSetAsideSummon, // A card was set aside (Summon) CardSetAsideGear, // A card was set aside (gear) CardSetAsideHaven, // A card was set aside (haven) CardSetAsideSave, // A card was set aside (save) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index bc6544593..5a8ce9a8c 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3730,6 +3730,11 @@ public ActionCard seaway_cardToObtain(MoveContext context) { return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); } + @Override + public ActionCard summon_cardToObtain(MoveContext context) { + return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); + } + public Card[] trade_cardsToTrash(MoveContext context) { return pickOutCards(context.getPlayer().getHand(), 2, getTrashCards()); } diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 7dea27a4f..39d19a3ce 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -107,6 +107,9 @@ public void isBuying(MoveContext context) { case Seaway: seaway(context); break; + case Summon: + summon(context); + break; case Trade: trade(context); break; @@ -418,6 +421,15 @@ private void seaway(MoveContext context) { } + private void summon(MoveContext context) { + ActionCard card = context.player.controlPlayer.summon_cardToObtain(context); + if (card != null) { + if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card)) { + context.player.gainNewCard(card, this.controlCard, context); + } + } + } + private void training(MoveContext context) { ActionCard card = context.getPlayer().controlPlayer.training_actionCardPileToHaveToken(context); placeToken(context, card, PlayerSupplyToken.PlusOneCoin); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 3f51cf2f0..3780769fc 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -839,6 +839,13 @@ protected void playerBeginTurn(Player player, MoveContext context) { durationCards.add(card); } } + for (Card card : player.summon) { + if (!card.equals(Cards.summon)) { + allDurationAreSimple = false; + durationCards.add(Cards.summon); + durationCards.add(card); + } + } while (!player.haven.isEmpty()) { /*gear could set 2 cards aside*/ durationCards.add((DurationCard) Cards.gear); @@ -866,13 +873,23 @@ protected void playerBeginTurn(Player player, MoveContext context) { durationCards.remove(selection+1); durationCards.remove(selection); - + if(card.equals(Cards.prince)) { if (!(card2 instanceof DurationCard)) { player.playedByPrince.add(card2); } player.prince.remove(card2); + context.freeActionInEffect++; + try { + ((ActionCardImpl) card2).play(this, context, false); + } catch (RuntimeException e) { + e.printStackTrace(); + } + context.freeActionInEffect--; + } else if(card.equals(Cards.summon)) { + player.summon.remove(card2); + context.freeActionInEffect++; try { ((ActionCardImpl) card2).play(this, context, false); @@ -2507,6 +2524,17 @@ public void gameEvent(GameEvent event) { player.putOnTopOfDeck(event.card, context, true); } else if (context.travellingFairBought && context.player.controlPlayer.royalSealTravellingFair_shouldPutCardOnDeck((MoveContext) context, Cards.travellingFair, event.card)) { player.putOnTopOfDeck(event.card, context, true); + } else if (event.responsible != null && event.responsible.equals(Cards.summon) + && (!event.card.equals(Cards.inn)) + && (!event.card.equals(Cards.borderVillage) || (event.card.equals(Cards.borderVillage) && Cards.borderVillage.getCost(context) == 0)) + && (!event.card.equals(Cards.deathCart) || (event.card.equals(Cards.deathCart) && context.game.isPileEmpty(Cards.virtualRuins))) + ) { + //TODO: figure out better way to handle not Summoning Death Cart or Border Village (or other cards) due to lose track rule + // may have missed some esoteric cases here (e.g. Inn's when-gain ability doesn't have to have Summon lose track) + context.player.summon.add(event.card); + GameEvent summonEvent = new GameEvent(GameEvent.Type.CardSetAsideSummon, context); + summonEvent.card = event.card; + context.game.broadcastEvent(summonEvent); } else if (event.card.equals(Cards.nomadCamp)) { player.putOnTopOfDeck(event.card, context, true); } else if (event.responsible != null) { @@ -2633,8 +2661,8 @@ public void gameEvent(GameEvent event) { player.discard.remove(c); player.deck.add(c); } - player.shuffleDeck(context, event.card); } + player.shuffleDeck(context, event.card); } else if (event.card.equals(Cards.borderVillage)) { boolean validCard = false; diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index d0a835d01..6e5719ced 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -3030,6 +3030,16 @@ public ActionCard seaway_cardToObtain(MoveContext context) { return (ActionCard) getFromTable(context, sco); } + @Override + public ActionCard summon_cardToObtain(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_summon_cardToObtain(context)) { + return super.summon_cardToObtain(context); + } + SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) + .setCardResponsible(Cards.summon).isAction().setActionType(ActionType.GAIN); + return (ActionCard) getFromTable(context, sco); + } + @Override public Card[] trade_cardsToTrash(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_trade_cardsToTrash(context)) { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 2f04b7d8b..42db37d54 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -51,6 +51,7 @@ public abstract class Player { protected CardList nativeVillage; protected CardList tavern; protected CardList prince; + protected CardList summon; protected CardList island; protected CardList haven; protected CardList horseTraders; @@ -242,6 +243,7 @@ public void initCards() { nativeVillage = new CardList(this, "Native Village"); tavern = new CardList(this, "Tavern"); prince = new CardList(this, "Prince"); + summon = new CardList(this, "Summon"); playedByPrince = new CardList(this, "PlayedByPrince"); island = new CardList(this, "Island"); haven = new CardList(this, "Haven"); @@ -520,6 +522,10 @@ public CardList getIsland() { public CardList getPrince() { return prince; } + + public CardList getSummon() { + return summon; + } public CardList getPlayedByPrince() { return playedByPrince; @@ -642,6 +648,9 @@ public ArrayList getAllCards() { for (Card card : prince) { allCards.add(card); } + for (Card card : summon) { + allCards.add(card); + } for (Card card : horseTraders) { allCards.add(card); } @@ -1828,6 +1837,7 @@ public ArrayList getActionsInHand() { public abstract Card save_cardToSetAside(MoveContext context); public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); public abstract ActionCard seaway_cardToObtain(MoveContext context); + public abstract ActionCard summon_cardToObtain(MoveContext context); public abstract ActionCard training_actionCardPileToHaveToken(MoveContext context); public abstract Card trashingToken_cardToTrash(MoveContext context); public abstract Card[] trade_cardsToTrash(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 41cc9e16c..8d61374c0 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -967,6 +967,10 @@ public boolean shouldAutoPlay_seaway_cardToObtain(MoveContext context) { return false; } + public boolean shouldAutoPlay_summon_cardToObtain(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_trade_cardsToTrash(MoveContext context) { return false; } diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 3cc13552d..3f2482453 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -215,7 +215,7 @@ public static void dumpGameState(MoveContext context) { } log(""); log("Deck:" + player.getDeckSize() + " PirateShip:" + player.getPirateShipTreasure() + " NativeVillage:" + cardArrayToString(player.getNativeVillage()) - + " Island:" + cardArrayToString(player.getIsland()) + " Prince:" + cardArrayToString(player.getPrince())); + + " Island:" + cardArrayToString(player.getIsland()) + " Prince:" + cardArrayToString(player.getPrince()) + " Summon:" + cardArrayToString(player.getSummon())); log(""); } From 2994c3ee6c2208036e13594694b10de436e26a35 Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 21 Jan 2016 00:31:40 -0700 Subject: [PATCH 046/141] Interleave Reserves with other start of turn effects. Allowing Events to cause Prince to lose track of cards. --- androminion/res/values/strings-server.xml | 2 ++ .../com/mehtank/androminion/ui/Strings.java | 7 +++- vdom/src/com/vdom/core/EventCardImpl.java | 3 ++ vdom/src/com/vdom/core/Game.java | 32 +++++++++++++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 230a6c6ff..fa3572cfb 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -434,6 +434,8 @@ Gaining %1$s. Call card: %1$s resolved. Call card: Start of turn. Call card: + Start of turn. Pick action: + %1$s (optional) Place Stash in deck Place %1$s Stash cards in deck diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index a9be275f0..cf6701448 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -24,6 +24,7 @@ import com.vdom.comms.SelectCardOptions; import com.vdom.comms.SelectCardOptions.ActionType; import com.vdom.comms.SelectCardOptions.PickType; +import com.vdom.core.CallableCard; import com.vdom.core.Cards; import com.vdom.core.IndirectPlayer; import com.vdom.core.IndirectPlayer.StashOption; @@ -498,6 +499,8 @@ public static String[] getOptions(Card card, Object[] options) { } else if(((Card)options[i]).equals(Cards.horseTraders)) { strings2[(i - startIndex)/2] = "\u261e" + getCardName((Card)options[i]) + ", \u261e" + getString(R.string.pawn_one); + } else if(options[i] instanceof CallableCard && ((CallableCard)options[i]).isCallableWhenTurnStarts()) { + strings2[(i - startIndex)/2] = format(R.string.call_optional, getCardName((Card)options[i])); } else { strings2[(i - startIndex)/2] = getCardName((Card)options[i]); } @@ -634,8 +637,10 @@ public static String getSelectOptionHeader(Card card, Object[] extras) { } } else if (cardName.equals(getCardName(Cards.envoy))) { return getActionString(ActionType.OPPONENTDISCARD, card, (String) extras[0]); - } else if (cardName.equals(getCardName(Cards.golem)) || cardName.equals(getCardName(Cards.prince))) { + } else if (cardName.equals(getCardName(Cards.golem))) { return getString(R.string.golem_first_action); + } else if (cardName.equals(getCardName(Cards.prince))) { // Prince signifies all start of turn effects + return getString(R.string.start_turn_query); } else if (cardName.equals(getCardName(Cards.herald))) { return getString(R.string.herald_overpay_query) + " [" + cardName + "]"; } else if (cardName.equals(getCardName(Cards.herbalist))) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 39d19a3ce..b91ac1f00 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -121,6 +121,9 @@ public void isBuying(MoveContext context) { default: break; } + + // test if prince lost track of any cards + context.player.princeCardLeftThePlay(context.player); } public void alms(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 3780769fc..a89934fac 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -851,8 +851,29 @@ protected void playerBeginTurn(Player player, MoveContext context) { durationCards.add((DurationCard) Cards.gear); durationCards.add(player.haven.remove(0)); } + int numOptionalItems = 0; + if (!allDurationAreSimple) { + // Add cards callable at start of turn + ArrayList callableCards = new ArrayList(); + for (Card c : player.tavern) { + if (c.behaveAsCard() instanceof CallableCard) { + CallableCard card = (CallableCard)(c.behaveAsCard()); + if (!card.isCallableWhenTurnStarts()) + continue; + callableCards.add((CallableCard) c); + } + } + if (!callableCards.isEmpty()) { + Collections.sort(callableCards, new Util.CardCostComparator()); + for (Card c : callableCards) { + durationCards.add(c); + durationCards.add(Cards.curse); + numOptionalItems += 2; + } + } + } - while (!durationCards.isEmpty()) { + while (durationCards.size() > numOptionalItems) { int selection=0; if(allDurationAreSimple) { selection=0; @@ -944,6 +965,10 @@ protected void playerBeginTurn(Player player, MoveContext context) { } context.freeActionInEffect--; } + } else if(card.behaveAsCard() instanceof CallableCard + && ((CallableCard)card.behaveAsCard()).isCallableWhenTurnStarts()) { + numOptionalItems -= 2; + ((CallableCard)card.behaveAsCard()).callAtStartOfTurn(context); } else { Util.log("ERROR: nextTurnCards contains " + card); } @@ -986,9 +1011,10 @@ protected void playerBeginTurn(Player player, MoveContext context) { player.nextTurnCards.add(staysInPlayCards.remove(0)); } - //TODO: Dominionator - integrate this with other start of turn logic - // Will require tracking duration effects independent of cards + //TODO: Dominionator - Will require tracking duration effects independent of cards + // to do correctly - do this later. + //TODO: integrate this into the main action selection UI if possible to make it more seamless //check for start-of-turn callable cards ArrayList callableCards = new ArrayList(); CallableCard toCall = null; From b871b0047925cbcf30cd97a10cb59cff93f5c689 Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 21 Jan 2016 23:21:12 -0700 Subject: [PATCH 047/141] Swamp Hag / Haunted Woods correct effect tracking. Now tracks defense and effects correctly even if you Moat only one of multiple Haunted Woods. --- androminion/res/values/strings-server.xml | 6 +++--- vdom/src/com/vdom/core/ActionCardImpl.java | 17 +++++++++++++++ vdom/src/com/vdom/core/Game.java | 23 +++++++------------- vdom/src/com/vdom/core/Player.java | 25 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index fa3572cfb..f2d54103d 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -423,9 +423,9 @@ Select number of Copper cards to put into your hand - Haunted Woods in play - %1$s Swamp Hag in play - %1$s Swamp Hags in play + Haunted Woods in effect + %1$s Swamp Hag in effect + %1$s Swamp Hags in effect Exchange it for %1$s move your token to (without your tokens on it). [Teacher] Discard from Tavern diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 598503598..cd49d519a 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -823,6 +823,9 @@ protected void additionalCardActions(Game game, MoveContext context, Player curr case Giant: giant(game, context, currentPlayer); break; + case HauntedWoods: + swampHagHauntedWoods(game, context, currentPlayer); + break; case Hero: hero(game, context, currentPlayer); break; @@ -847,6 +850,9 @@ protected void additionalCardActions(Game game, MoveContext context, Player curr case Storyteller: storyteller(game, context, currentPlayer); break; + case SwampHag: + swampHagHauntedWoods(game, context, currentPlayer); + break; case TreasureHunter: treasureHunter(game, context, currentPlayer); break; @@ -6387,6 +6393,17 @@ private void storyteller(Game game, MoveContext context, Player currentPlayer) { } } + private void swampHagHauntedWoods(Game game, MoveContext context, Player currentPlayer) { + for (Player targetPlayer : context.game.getPlayersInTurnOrder()) { + if (targetPlayer != currentPlayer) { + if (!Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + targetPlayer.attacked(this.controlCard, context); + currentPlayer.addDurationEffectOnOtherPlayer(targetPlayer, this.type); + } + } + } + } + private void treasureHunter(Game game, MoveContext context, Player currentPlayer) { for (int i = 0; i < context.getCardsObtainedByLastPlayer().size(); i++) { currentPlayer.gainNewCard(Cards.silver, this, context); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index a89934fac..176e70ea0 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -770,10 +770,13 @@ protected void playerBeginTurn(Player player, MoveContext context) { player.controlPlayer = player; consecutiveTurnCounter++; } - + cardsObtainedLastTurn[playersTurn].clear(); if (consecutiveTurnCounter == 1) player.newTurn(); + + player.clearDurationEffectsOnOtherPlayers(); + GameEvent gevent = new GameEvent(GameEvent.Type.TurnBegin, context); broadcastEvent(gevent); @@ -1531,13 +1534,11 @@ Card playBuy(MoveContext context, Card buy) { } } - /*frr18 todo defense */ for (int i=0; i < swampHagAttacks(player); i++) { player.gainNewCard(Cards.curse, Cards.swampHag, context); } if (hauntedWoodsAttacks(player)) { - /*frr18 todo defense */ if(player.hand.size() > 0) { Card[] order; if (player.hand.size() == 1) @@ -3264,14 +3265,11 @@ public void trashHovelsInHandOption(Player player, MoveContext context, Card res public boolean hauntedWoodsAttacks(Player player) { - /*frr18 todo defense */ for (Player otherPlayer : players) { if (otherPlayer != null && otherPlayer != player) { - for (Card card : otherPlayer.nextTurnCards) { - if(card.equals(Cards.hauntedWoods)) { - return true; - } - } + if (otherPlayer.getDurationEffectsOnOtherPlayer(player, Cards.Type.HauntedWoods) > 0) { + return true; + } } } return false; @@ -3279,15 +3277,10 @@ public boolean hauntedWoodsAttacks(Player player) public int swampHagAttacks(Player player) { - /*frr18 todo defense */ int swampHags = 0; for (Player otherPlayer : players) { if (otherPlayer != null && otherPlayer != player) { - for (Card card : otherPlayer.nextTurnCards) { - if(card.equals(Cards.swampHag)) { - swampHags += ((CardImpl) card).cloneCount;; - } - } + swampHags += otherPlayer.getDurationEffectsOnOtherPlayer(player, Cards.Type.SwampHag); } } return swampHags; diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 42db37d54..b930b007a 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -56,6 +56,7 @@ public abstract class Player { protected CardList haven; protected CardList horseTraders; protected Card save; + protected Map> attackDurationEffectsOnOthers; public Game game; public Player controlPlayer = this; @@ -248,6 +249,7 @@ public void initCards() { island = new CardList(this, "Island"); haven = new CardList(this, "Haven"); horseTraders = new CardList(this, "Horse Traders"); + attackDurationEffectsOnOthers = new HashMap>(); } private List getPutBackOptions(MoveContext context, int actionsPlayed) { @@ -812,6 +814,29 @@ public Map getVictoryPointTotals(Map counts) { return totals; } + + public void clearDurationEffectsOnOtherPlayers() { + attackDurationEffectsOnOthers.clear(); + } + + public void addDurationEffectOnOtherPlayer(Player player, Cards.Type effectType) { + if (!attackDurationEffectsOnOthers.containsKey(player)) { + attackDurationEffectsOnOthers.put(player, new HashMap()); + } + Map otherPlayerEffects = attackDurationEffectsOnOthers.get(player); + if (!otherPlayerEffects.containsKey(effectType)) { + otherPlayerEffects.put(effectType, 0); + } + otherPlayerEffects.put(effectType, otherPlayerEffects.get(effectType) + 1); + } + + public int getDurationEffectsOnOtherPlayer(Player player, Cards.Type effectType) { + if (attackDurationEffectsOnOthers.containsKey(player) + && attackDurationEffectsOnOthers.get(player).containsKey(effectType)) { + return attackDurationEffectsOnOthers.get(player).get(effectType); + } + return 0; + } public Card peekAtDeckBottom() { return deck.get(deck.size() - 1); From 47eaaa18bc6df7e6ee407f48852ad784c75f6a33 Mon Sep 17 00:00:00 2001 From: dominionator Date: Fri, 22 Jan 2016 00:30:14 -0700 Subject: [PATCH 048/141] Fixed multiple duration modifier cards staying out with Hireling/Champion. --- vdom/src/com/vdom/core/Game.java | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 176e70ea0..1ce7b5a35 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -820,12 +820,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { durationCards.add(Cards.curse); /*dummy*/ } } - } else if( thisCard.equals(Cards.throneRoom) - || thisCard.equals(Cards.disciple) - || thisCard.equals(Cards.kingsCourt) - || thisCard.equals(Cards.procession) - || thisCard.equals(Cards.royalCarriage) - || thisCard.equals(Cards.bandOfMisfits)) { + } else if(isModifierCard(thisCard.behaveAsCard())) { GameEvent event = new GameEvent(GameEvent.Type.PlayingDurationAction, context); event.card = thisCard; broadcastEvent(event); @@ -980,25 +975,30 @@ protected void playerBeginTurn(Player player, MoveContext context) { ArrayList staysInPlayCards = new ArrayList(); while (!player.nextTurnCards.isEmpty()) { Card card = player.nextTurnCards.remove(0); - if( card.equals(Cards.throneRoom) - || card.equals(Cards.disciple) - || card.equals(Cards.kingsCourt) - || card.equals(Cards.procession) - || card.equals(Cards.royalCarriage) - || card.equals(Cards.bandOfMisfits)) - { + if(isModifierCard(card.behaveAsCard())) { if(!player.nextTurnCards.isEmpty()) { Card nextCard = player.nextTurnCards.get(0); - if(nextCard.getType() == Cards.Type.Hireling || nextCard.getType() == Cards.Type.Champion) { + int additionalModifierCards = 0; + while (nextCard != null && isModifierCard(nextCard.behaveAsCard())) { + additionalModifierCards++; + if (player.nextTurnCards.size() > additionalModifierCards) + nextCard = player.nextTurnCards.get(additionalModifierCards); + else + nextCard = null; + } + if(nextCard != null && (nextCard.behaveAsCard().equals(Cards.hireling) || nextCard.behaveAsCard().equals(Cards.champion))) { staysInPlayCards.add(card); + for (int i = 0; i < additionalModifierCards; ++i) { + staysInPlayCards.add(player.nextTurnCards.remove(0)); + } player.nextTurnCards.remove(0); - staysInPlayCards.add((DurationCard) nextCard); + staysInPlayCards.add(nextCard); continue; } } } - if(card.getType() == Cards.Type.Hireling || card.getType() == Cards.Type.Champion) { + if(card.behaveAsCard().equals(Cards.hireling) || card.behaveAsCard().equals(Cards.champion)) { staysInPlayCards.add((DurationCard) card); } else { CardImpl behaveAsCard = (CardImpl) card.behaveAsCard(); @@ -1046,7 +1046,15 @@ protected void playerBeginTurn(Player player, MoveContext context) { } } - private static void printStats(HashMap wins, int gameCount, String gameType) { + private boolean isModifierCard(Card card) { + return card.equals(Cards.throneRoom) + || card.equals(Cards.disciple) + || card.equals(Cards.kingsCourt) + || card.equals(Cards.procession) + || card.equals(Cards.royalCarriage); + } + + private static void printStats(HashMap wins, int gameCount, String gameType) { if (!test || gameCount == 1) { return; } From 3338baf41181e4b7a72b393b81a1de117a1d6f14 Mon Sep 17 00:00:00 2001 From: dominionator Date: Fri, 22 Jan 2016 23:41:20 -0700 Subject: [PATCH 049/141] Inheritance buying and UI (Estates don't yet function like set aside card) --- androminion/res/layout/view_hand.xml | 27 +++- androminion/res/values/strings-server.xml | 3 + androminion/res/values/strings-ui.xml | 1 + .../com/mehtank/androminion/ui/GameTable.java | 24 +++- .../androminion/ui/GameTableViews.java | 126 +++++++++--------- .../com/mehtank/androminion/ui/Strings.java | 10 +- vdom/src/com/vdom/api/GameEvent.java | 1 + vdom/src/com/vdom/comms/GameStatus.java | 2 + .../src/com/vdom/comms/SelectCardOptions.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 1 + vdom/src/com/vdom/core/BasePlayer.java | 6 + vdom/src/com/vdom/core/EventCardImpl.java | 15 +++ vdom/src/com/vdom/core/IndirectPlayer.java | 11 ++ vdom/src/com/vdom/core/MoveContext.java | 4 + vdom/src/com/vdom/core/Player.java | 8 ++ vdom/src/com/vdom/core/QuickPlayPlayer.java | 4 + vdom/src/com/vdom/core/RemotePlayer.java | 1 + vdom/src/com/vdom/core/Util.java | 6 +- 18 files changed, 182 insertions(+), 70 deletions(-) diff --git a/androminion/res/layout/view_hand.xml b/androminion/res/layout/view_hand.xml index c5ab07fb8..640ec78cc 100644 --- a/androminion/res/layout/view_hand.xml +++ b/androminion/res/layout/view_hand.xml @@ -177,6 +177,31 @@ android:verticalSpacing="@dimen/margin_cards" /> + + + + + + + + + + - + Select an Action card from the table that costs exactly (%1$s) to %2$s Select a card from the table that costs at most (%1$s) to %2$s Select a non-victory card from the table that costs at most (%1$s) to %2$s + Select a non-victory action card from the table that costs at most (%1$s) to %2$s Select a Victory card from the table that costs at most (%1$s) to %2$s Select an Action card from the table that costs at most (%1$s) to %2$s Select a card from the table that costs between (%1$s) and (%2$s) to %3$s @@ -103,6 +104,7 @@ discard [%1$s] for cards discard [%1$s] for coin name [%1$s] + set aside [%1$s] Discard Trash Keep @@ -155,6 +157,7 @@ Card set aside (Gear) Card set aside (Save) Card set aside on island mat + Card set aside (Inheritance) Deck put into discard pile Traveller exchanged for Journey token turned face up diff --git a/androminion/res/values/strings-ui.xml b/androminion/res/values/strings-ui.xml index 25abc979b..204a46898 100644 --- a/androminion/res/values/strings-ui.xml +++ b/androminion/res/values/strings-ui.xml @@ -175,6 +175,7 @@ Drag/drop\nthe cards to\nrearrange\ntheir order. Trash: Bl. Market: + Inherit: %1$s card art Downloading card art from %1$s A diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index ed3f743a5..410b7332b 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -49,9 +49,9 @@ public PlayerAdapter getPlayerAdapter() { return players; } - GridView handGV, playedGV, tavernGV, princeGV, islandGV, villageGV, blackMarketGV, trashGV; - CardGroup hand, played, tavern, prince, island, village, blackMarket, trash; - View tavernColumn, princeColumn, islandColumn, villageColumn, blackMarketColumn, trashColumn; + GridView handGV, playedGV, tavernGV, princeGV, islandGV, villageGV, inheritanceGV, blackMarketGV, trashGV; + CardGroup hand, played, tavern, prince, island, village, inheritance, blackMarket, trash; + View tavernColumn, princeColumn, islandColumn, villageColumn, inheritanceColumn, blackMarketColumn, trashColumn; TextView playedHeader; LinearLayout myCards; @@ -192,7 +192,13 @@ private void initHand() { villageGV.setAdapter(village); villageGV.setOnItemLongClickListener(this); villageColumn = findViewById(R.id.villageColumn); - + + inheritance = new CardGroup(top, false); + inheritanceGV = (GridView) findViewById(R.id.inheritanceGV); + inheritanceGV.setAdapter(inheritance); + inheritanceGV.setOnItemLongClickListener(this); + inheritanceColumn = findViewById(R.id.inheritanceColumn); + blackMarket = new CardGroup(top, false); blackMarketGV = (GridView) findViewById(R.id.blackMarketGV); blackMarketGV.setAdapter(blackMarket); @@ -324,6 +330,7 @@ public void newGame(MyCard[] cards, String[] players) { village.clear(); trash.clear(); blackMarket.clear(); + inheritance.clear(); this.players.clear(); actionText.setText(""); @@ -1061,13 +1068,20 @@ public void setStatus(GameStatus gs, Object[] objects, Event event) { villageColumn.setVisibility(GONE); } + GameTableViews.newSingleCardGroup(inheritance, gs.myInheritance); + if (gs.myInheritance >= 0) { + inheritanceColumn.setVisibility(VISIBLE); + } else { + inheritanceColumn.setVisibility(GONE); + } + GameTableViews.newCardGroup(blackMarket, gs.blackMarketPile); if (gs.blackMarketPile.length > 0) { blackMarketColumn.setVisibility(VISIBLE); } else { blackMarketColumn.setVisibility(GONE); } - + GameTableViews.newCardGroup(trash, gs.trashPile); if (gs.trashPile.length > 0) { trashColumn.setVisibility(VISIBLE); diff --git a/androminion/src/com/mehtank/androminion/ui/GameTableViews.java b/androminion/src/com/mehtank/androminion/ui/GameTableViews.java index 902aec5ee..9c5a4a6ec 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTableViews.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTableViews.java @@ -1,33 +1,33 @@ -package com.mehtank.androminion.ui; - -import java.util.ArrayList; - +package com.mehtank.androminion.ui; + +import java.util.ArrayList; + import com.mehtank.androminion.R; -import com.mehtank.androminion.util.CardGroup; -import com.vdom.comms.MyCard; - -import android.content.Context; -import android.view.View; -import android.widget.GridView; -import android.widget.LinearLayout; -import android.widget.TextView; - +import com.mehtank.androminion.util.CardGroup; +import com.vdom.comms.MyCard; + +import android.content.Context; +import android.view.View; +import android.widget.GridView; +import android.widget.LinearLayout; +import android.widget.TextView; + /** * Keeps track of all the cards in play */ -public class GameTableViews { +public class GameTableViews { @SuppressWarnings("unused") private static final String TAG = "GameTableViews"; - static double textScale = 0.8; - static ArrayList cardsInPlay = new ArrayList(); - - static void clearCards() { - cardsInPlay.clear(); - } - static void addCard(int id, MyCard c) { - cardsInPlay.add(id, c); - } + static double textScale = 0.8; + static ArrayList cardsInPlay = new ArrayList(); + + static void clearCards() { + cardsInPlay.clear(); + } + static void addCard(int id, MyCard c) { + cardsInPlay.add(id, c); + } /** * Generate a GridView * @param top GameActivity @@ -35,18 +35,18 @@ static void addCard(int id, MyCard c) { * @param n Number of columns. If this is one, the card width will be fixed, otherwise the table will stretch to fit * @return the generated GridView */ - static GridView makeGV(Context top, CardGroup a, int n) { - GridView gv = new GridView(top); - gv.setAdapter(a); - gv.setNumColumns(n); - if (n == 1) { + static GridView makeGV(Context top, CardGroup a, int n) { + GridView gv = new GridView(top); + gv.setAdapter(a); + gv.setNumColumns(n); + if (n == 1) { gv.setColumnWidth((int) top.getResources().getDimension(R.dimen.cardWidth)); - gv.setStretchMode(GridView.NO_STRETCH); - } else { - gv.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); - } - return gv; - } + gv.setStretchMode(GridView.NO_STRETCH); + } else { + gv.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); + } + return gv; + } /** * Generate LinearLayout with given title @@ -57,34 +57,40 @@ static GridView makeGV(Context top, CardGroup a, int n) { * @param title Header TextView, will be showing header * @return the LinearLayout */ - static LinearLayout myCardSet(Context top, String header, View v, TextView title) { - LinearLayout ll = new LinearLayout(top); - ll.setOrientation(LinearLayout.VERTICAL); - - if(title == null) - title = new TextView(top); - title.setTextSize(10.0f); - title.setText(header); - - ll.addView(title); - ll.addView(v); - - return ll; - } - + static LinearLayout myCardSet(Context top, String header, View v, TextView title) { + LinearLayout ll = new LinearLayout(top); + ll.setOrientation(LinearLayout.VERTICAL); + + if(title == null) + title = new TextView(top); + title.setTextSize(10.0f); + title.setText(header); + + ll.addView(title); + ll.addView(v); + + return ll; + } + /** * Fill the CardGroup object * @param cg CardGroup to fill * @param cards Array of Card-IDs */ - public static void newCardGroup(CardGroup cg, int[] cards) { - cg.clear(); - for (int c : cards) { - cg.addCard(cardsInPlay.get(Math.abs(c)), Math.signum(c) >= 0); - } - } - - public static CardView getCardView(Context context, GameTable gt, int card) { - return new CardView(context, null, cardsInPlay.get(card)); - } -} + public static void newCardGroup(CardGroup cg, int[] cards) { + cg.clear(); + for (int c : cards) { + cg.addCard(cardsInPlay.get(Math.abs(c)), Math.signum(c) >= 0); + } + } + + public static void newSingleCardGroup(CardGroup cg, int card) { + cg.clear(); + if (card >= 0) + cg.addCard(cardsInPlay.get(card)); + } + + public static CardView getCardView(Context context, GameTable gt, int card) { + return new CardView(context, null, cardsInPlay.get(card)); + } +} diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index cf6701448..c7570e073 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -293,6 +293,8 @@ public static String getStatusText(Event event, Object[] extras) { statusText += getString(R.string.CalledCard); } else if (event.gameEventType == GameEvent.Type.CardSetAsideOnIslandMat) { statusText += getString(R.string.CardSetAsideOnIslandMat); + } else if (event.gameEventType == GameEvent.Type.CardSetAsideInheritance) { + statusText += getString(R.string.CardSetAsideInheritance); } else if (event.gameEventType == GameEvent.Type.DeckPutIntoDiscardPile) { statusText += getString(R.string.DeckPutIntoDiscardPile); } else if (event.gameEventType == GameEvent.Type.TravellerExchanged) { @@ -1122,7 +1124,11 @@ else if (sco.minCost == sco.maxCost) { if (sco.isVictory) { selectString = Strings.format(R.string.select_from_table_max_vp, maxCostString, header); } else if (sco.isNonVictory) { - selectString = Strings.format(R.string.select_from_table_max_non_vp, maxCostString, header); + if (sco.isAction) { + selectString = Strings.format(R.string.select_from_table_max_non_vp_action, maxCostString, header); + } else { + selectString = Strings.format(R.string.select_from_table_max_non_vp, maxCostString, header); + } } else if (sco.isTreasure) { selectString = Strings.format(R.string.select_from_table_max_treasure, maxCostString, header); } else if (sco.isAction) { @@ -1229,6 +1235,7 @@ public static String getActionString(ActionType action, Card cardResponsible, St case TRASH: return Strings.format(R.string.card_to_trash, getCardName(cardResponsible)); case NAMECARD: return Strings.format(R.string.card_to_name, getCardName(cardResponsible)); case OPPONENTDISCARD: return Strings.format(R.string.opponent_discard, opponentName, getCardName(cardResponsible)); + case SETASIDE: return Strings.format(R.string.card_to_set_aside, getCardName(cardResponsible)); } return null; } @@ -1309,6 +1316,7 @@ private static void initActionStrings() { /*Adventures Events*/ getCardName(Cards.alms), getCardName(Cards.ball), + getCardName(Cards.inheritance), getCardName(Cards.pilgrimage), getCardName(Cards.seaway), /*Promo Events*/ diff --git a/vdom/src/com/vdom/api/GameEvent.java b/vdom/src/com/vdom/api/GameEvent.java index d699eb6ff..d0278f678 100644 --- a/vdom/src/com/vdom/api/GameEvent.java +++ b/vdom/src/com/vdom/api/GameEvent.java @@ -48,6 +48,7 @@ public enum Type { CallingCard, // A card is about to be called from the tavern mat CalledCard, // A card was called from the tavern mat CardSetAsideOnIslandMat, // A card was set aside on island mat + CardSetAsideInheritance, // A card was set aside with Inheritance DeckPutIntoDiscardPile, // Deck put into discard pile TravellerExchanged, // traveller exchanged TurnJourneyTokenFaceUp, // journey token turned face up diff --git a/vdom/src/com/vdom/comms/GameStatus.java b/vdom/src/com/vdom/comms/GameStatus.java index 33298a1ea..53111949e 100644 --- a/vdom/src/com/vdom/comms/GameStatus.java +++ b/vdom/src/com/vdom/comms/GameStatus.java @@ -20,6 +20,7 @@ public class GameStatus implements Serializable { public int[] myPrince; public int[] myIsland; public int[] myVillage; + public int myInheritance = -1; public int[] trashPile; public int[] blackMarketPile; public int[] blackMarketPileShuffled; @@ -62,6 +63,7 @@ public class GameStatus implements Serializable { public GameStatus setPrince(int[] is) {myPrince = is; return this;}; public GameStatus setIsland(int[] is) {myIsland = is; return this;}; public GameStatus setVillage(int[] is) {myVillage = is; return this;}; + public GameStatus setInheritance(int is) {myInheritance = is; return this;}; public GameStatus setTurnStatus(int[] is) {turnStatus = is; return this;}; public GameStatus setSupplySizes(int[] is) {supplySizes = is; return this;}; public GameStatus setEmbargos(int[] is) {embargos = is; return this;}; diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index 013671f43..36bdad562 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -21,7 +21,7 @@ public class SelectCardOptions implements Serializable { private static final long serialVersionUID = -1473106875075390348L; public enum ActionType { - REVEAL, DISCARD, DISCARDFORCOIN, DISCARDFORCARD, GAIN, TRASH, NAMECARD, OPPONENTDISCARD + REVEAL, DISCARD, DISCARDFORCOIN, DISCARDFORCARD, GAIN, TRASH, NAMECARD, OPPONENTDISCARD, SETASIDE } public enum PickType { diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index cd49d519a..0ecac9515 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -5145,6 +5145,7 @@ else if (gainEstates) break; case Fortress: + //TODO: if Possessed, give choice of whether to put in hand or set aside card context.game.trashPile.remove(this.controlCard); context.player.hand.add(this.controlCard); break; diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 5a8ce9a8c..450ddd0db 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -3617,6 +3617,12 @@ public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); } + @Override + public ActionCard inheritance_actionCardTosetAside(MoveContext context) { + //TODO: favor cantrips + return (ActionCard) bestCardInPlay(context, 4, false, false, true, false, true); + } + @Override public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index b91ac1f00..a711a796a 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -77,6 +77,9 @@ public void isBuying(MoveContext context) { case Ferry: ferry(context); break; + case Inheritance: + inheritance(context); + break; case LostArts: lostArts(context); break; @@ -191,6 +194,18 @@ private void ferry(MoveContext context) { placeToken(context, card, PlayerSupplyToken.MinusTwoCost); } + private void inheritance(MoveContext context) { + ActionCard card = context.getPlayer().controlPlayer.inheritance_actionCardTosetAside(context); + if (card != null) { + if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card) && !card.isVictory(context)) { + context.player.inheritance = context.game.takeFromPile(card, context); + GameEvent event = new GameEvent(GameEvent.Type.CardSetAsideInheritance, context); + event.card = card; + context.game.broadcastEvent(event); + } + } + } + private void lostArts(MoveContext context) { ActionCard card = context.getPlayer().controlPlayer.lostArts_actionCardPileToHaveToken(context); placeToken(context, card, PlayerSupplyToken.PlusOneAction); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 6e5719ced..25ca82c43 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -2929,6 +2929,17 @@ public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { return (ActionCard) getFromTable(context, sco); } + @Override + public ActionCard inheritance_actionCardTosetAside(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_inheritance_actionCardTosetAside(context)) { + return super.inheritance_actionCardTosetAside(context); + } + SelectCardOptions sco = new SelectCardOptions() + .isAction().isNonVictory().maxCost(4).potionCost(0) + .setActionType(ActionType.SETASIDE).setCardResponsible(Cards.inheritance); + return (ActionCard) getFromTable(context, sco); + } + @Override public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_lostArts_actionCardPileToHaveToken(context)) { diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index 2d1666b0c..ccae9f6b6 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -68,6 +68,8 @@ public MoveContext(Game game, Player player, boolean canBuyCards) { this.game = game; this.player = player; this.canBuyCards = canBuyCards; + if (player.getInheritance() != null) + cantBuy.add(Cards.inheritance); // this.playedCards = player.playedCards; } @@ -77,6 +79,8 @@ public MoveContext(MoveContext context, Game game, Player player) { this.coins = context.coins; this.game = game; this.player = player; + if (player.getInheritance() != null) + cantBuy.add(Cards.inheritance); } public Player getPlayer() { diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index b930b007a..7ca615b75 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -55,6 +55,7 @@ public abstract class Player { protected CardList island; protected CardList haven; protected CardList horseTraders; + protected Card inheritance; protected Card save; protected Map> attackDurationEffectsOnOthers; public Game game; @@ -249,6 +250,7 @@ public void initCards() { island = new CardList(this, "Island"); haven = new CardList(this, "Haven"); horseTraders = new CardList(this, "Horse Traders"); + inheritance = null; attackDurationEffectsOnOthers = new HashMap>(); } @@ -528,6 +530,10 @@ public CardList getPrince() { public CardList getSummon() { return summon; } + + public Card getInheritance() { + return inheritance; + } public CardList getPlayedByPrince() { return playedByPrince; @@ -656,6 +662,7 @@ public ArrayList getAllCards() { for (Card card : horseTraders) { allCards.add(card); } + allCards.add(inheritance); if (checkLeadCard != null) { allCards.add(checkLeadCard); } @@ -1852,6 +1859,7 @@ public ArrayList getActionsInHand() { public abstract Card ball_cardToObtain(MoveContext context); public abstract Card[] bonfire_cardsToTrash(MoveContext context); public abstract ActionCard ferry_actionCardPileToHaveToken(MoveContext context); + public abstract ActionCard inheritance_actionCardTosetAside(MoveContext context); public abstract ActionCard lostArts_actionCardPileToHaveToken(MoveContext context); public abstract ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context); public abstract Card[] pilgrimage_cardsToGain(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 8d61374c0..1c6933a14 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -927,6 +927,10 @@ public boolean shouldAutoPlay_ferry_actionCardPileToHaveToken(MoveContext contex return false; } + public boolean shouldAutoPlay_inheritance_actionCardTosetAside(MoveContext context) { + return false; + } + public boolean shouldAutoPlay_lostArts_actionCardPileToHaveToken(MoveContext context) { return false; } diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 23b11a0b5..3c267e7bf 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -461,6 +461,7 @@ else if (cardsInPlay.get(i).isKnight()) .setPrince(cardArrToIntArr(player.getPrince().toArray())) .setIsland(cardArrToIntArr(player.getIsland().toArray())) .setVillage(player.equals(this) ? cardArrToIntArr(player.getNativeVillage().toArray()) : new int[0]/*show empty Village*/) + .setInheritance(player.inheritance == null ? -1 : cardToInt(player.inheritance)) .setBlackMarket(arrayListToIntArr(player.game.GetBlackMarketPile())) .setTrash(arrayListToIntArr(player.game.GetTrashPile())); diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 3f2482453..f56713a6e 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -214,8 +214,10 @@ public static void dumpGameState(MoveContext context) { cost++; } log(""); - log("Deck:" + player.getDeckSize() + " PirateShip:" + player.getPirateShipTreasure() + " NativeVillage:" + cardArrayToString(player.getNativeVillage()) - + " Island:" + cardArrayToString(player.getIsland()) + " Prince:" + cardArrayToString(player.getPrince()) + " Summon:" + cardArrayToString(player.getSummon())); + log("Deck:" + player.getDeckSize() + " PirateShip:" + player.getPirateShipTreasure() + + " NativeVillage:" + cardArrayToString(player.getNativeVillage()) + + " Island:" + cardArrayToString(player.getIsland()) + " Prince:" + cardArrayToString(player.getPrince()) + + " Summon:" + cardArrayToString(player.getSummon()) + " Inheritance:" + player.getInheritance()); log(""); } From c81f53c0c54ecd7d8c97719efa89f87db5cec5f5 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 23 Jan 2016 02:02:26 -0700 Subject: [PATCH 050/141] Adding messages around buying events. Updated version and related information. --- androminion/AndroidManifest.xml | 4 ++-- .../res/values/strings-international.xml | 5 ++-- androminion/res/values/strings-server.xml | 2 ++ androminion/res/values/strings-ui.xml | 3 +++ .../androminion/ui/GameTableViews.java | 4 ++++ .../com/mehtank/androminion/ui/Strings.java | 24 +++++++++++++++++-- 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/androminion/AndroidManifest.xml b/androminion/AndroidManifest.xml index f52738a33..ad55d40c5 100644 --- a/androminion/AndroidManifest.xml +++ b/androminion/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="603" + android:versionName="6.03" > \n©2010–2013 by Ankur Mehta\nhttp://android.mehtank.com - \nDominion card game ©2008–2013 by Rio Grande Games. + \nDominion card game ©2008–2015 by Rio Grande Games. \nTodd Barlow \nMartin Binder \nDrew Chamberlain @@ -21,7 +21,8 @@ \nTom Shelley \nMaxim Tkachenko \nJörg Velletti - \nEiko Wagenknecht + \nEiko Wagenknecht + \nDominionator ~~~\n \ No newline at end of file diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 2b23e49f5..4569da896 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -58,6 +58,8 @@ Select a card from the table that costs exactly (%1$s) to %2$s Select an Action card from the table that costs exactly (%1$s) to %2$s Select a card from the table that costs at most (%1$s) to %2$s + Select an event from the table that costs at most (%1$s) to %2$s + Select a card or event from the table that costs at most (%1$s) to %2$s Select a non-victory card from the table that costs at most (%1$s) to %2$s Select a non-victory action card from the table that costs at most (%1$s) to %2$s Select a Victory card from the table that costs at most (%1$s) to %2$s diff --git a/androminion/res/values/strings-ui.xml b/androminion/res/values/strings-ui.xml index 204a46898..16d30ff8f 100644 --- a/androminion/res/values/strings-ui.xml +++ b/androminion/res/values/strings-ui.xml @@ -52,6 +52,9 @@ Rio Grande Games, the publisher of Dominion, has asked us to discontinue Androminion as they launch their official digital version of the game. As such, this will (probably) be the last major revision; Androminion will be removed from the market soon. Thanks to all of you who have contributed to the project, submitted bug reports, or spread the word -- without you Androminion would not be as polished and popular as it is today.

On behalf of the Androminion team, it has been fun.
-:ankur +

Version 6.03

+ * Adventures Expansion! + * Promo Cards: Stash, Summon

Version 6.00

* Adventures (beta)

Version 5.01

diff --git a/androminion/src/com/mehtank/androminion/ui/GameTableViews.java b/androminion/src/com/mehtank/androminion/ui/GameTableViews.java index 9c5a4a6ec..7c832d80b 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTableViews.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTableViews.java @@ -93,4 +93,8 @@ public static void newSingleCardGroup(CardGroup cg, int card) { public static CardView getCardView(Context context, GameTable gt, int card) { return new CardView(context, null, cardsInPlay.get(card)); } + + public static MyCard intToMyCard(int card) { + return cardsInPlay.get(card); + } } diff --git a/androminion/src/com/mehtank/androminion/ui/Strings.java b/androminion/src/com/mehtank/androminion/ui/Strings.java index c7570e073..beee2560b 100644 --- a/androminion/src/com/mehtank/androminion/ui/Strings.java +++ b/androminion/src/com/mehtank/androminion/ui/Strings.java @@ -1133,8 +1133,12 @@ else if (sco.minCost == sco.maxCost) { selectString = Strings.format(R.string.select_from_table_max_treasure, maxCostString, header); } else if (sco.isAction) { selectString = Strings.format(R.string.select_from_table_max_action, maxCostString, header); - } else { + } else if (containsOnlyEvents(sco)) { + selectString = Strings.format(R.string.select_from_table_max_events, maxCostString, header); + } else if (containsOnlyCards(sco)) { selectString = Strings.format(R.string.select_from_table_max, maxCostString, header); + } else { + selectString = Strings.format(R.string.select_from_table_max_cards_events, maxCostString, header); } } else if (sco.minCost > 0 && sco.maxCost < Integer.MAX_VALUE) { selectString = Strings.format(R.string.select_from_table_between, minCostString, maxCostString, header); @@ -1208,7 +1212,23 @@ else if(sco.exactCount) throw new RuntimeException("SelectCardOptions isn't from table or from hand or from played..."); } - public static String getActionString(SelectCardOptions sco) { + private static boolean containsOnlyCards(SelectCardOptions sco) { + for (int cardId : sco.allowedCards) { + if (GameTableViews.intToMyCard(cardId).isEvent) + return false; + } + return true; + } + + private static boolean containsOnlyEvents(SelectCardOptions sco) { + for (int cardId : sco.allowedCards) { + if (!GameTableViews.intToMyCard(cardId).isEvent) + return false; + } + return true; + } + + public static String getActionString(SelectCardOptions sco) { return getActionString(sco.actionType, sco.cardResponsible); } From 0ddc2e44f72b4772481a24561ed1fe7e39b834b8 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sat, 23 Jan 2016 23:33:15 -0700 Subject: [PATCH 051/141] Changing shaded cards in UI for Bonfire and Pilgrimage. Cards in UI show as shaded if they don't represent cards that are actually in play (e.g. cards played and removed from play and throned duration effects and those from trashed card show as shaded). Allowing Bonfire to trash Duration cards and their modifier cards. Fixed issue with Royal Carriage causing too many plays when calling between plays of a Throne-variant effect. --- .../com/mehtank/androminion/ui/GameTable.java | 10 ++- vdom/src/com/vdom/core/ActionCardImpl.java | 6 +- .../com/vdom/core/CallableActionCardImpl.java | 6 +- vdom/src/com/vdom/core/EventCardImpl.java | 16 +++- vdom/src/com/vdom/core/Game.java | 86 ++++++++++++------- vdom/src/com/vdom/core/MoveContext.java | 1 + vdom/src/com/vdom/core/RemotePlayer.java | 57 ++++++++++-- vdom/src/com/vdom/core/TreasureCardImpl.java | 9 +- 8 files changed, 140 insertions(+), 51 deletions(-) diff --git a/androminion/src/com/mehtank/androminion/ui/GameTable.java b/androminion/src/com/mehtank/androminion/ui/GameTable.java index 410b7332b..7e42ece2b 100644 --- a/androminion/src/com/mehtank/androminion/ui/GameTable.java +++ b/androminion/src/com/mehtank/androminion/ui/GameTable.java @@ -481,9 +481,11 @@ private void cannotSelect() { * @param parent which pile the card was selected from * @return */ - boolean isAcceptable(MyCard c, CardGroup parent) { + boolean isAcceptable(CardState cs, CardGroup parent) { + MyCard c = cs.c; + if (cs.shade) return false; if (sco.fromHand && (parent != hand)) return false; - else if (sco.fromPlayed && (parent != played)) return false; // TODO: prevent throned plays from being selected from played group + else if (sco.fromPlayed && (parent != played)) return false; else if (sco.fromTable) { // if (!sco.allowEmpty) { // if (lastSupplySizes[c.id] == 0) @@ -572,7 +574,7 @@ public void cardSelected(Button b) { 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)) + if (!isAcceptable(ci.cs, ci.parent)) return; cards[i] = ci.cs.c.id; } @@ -1214,7 +1216,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) } } } else { - if (isAcceptable(clickedCard.getCard(), clickedCard.parent)) { + if (isAcceptable(clickedCard.getState(), clickedCard.parent)) { HapticFeedback.vibrate(getContext(), AlertType.CLICK); if (sco.isDifferent() && hasDuplicate(openedCards, clickedCard.getState().c)) { int duplicateIndex = getFirstIndex(openedCards, clickedCard.getState().c); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 0ecac9515..47b7f43f2 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1827,8 +1827,10 @@ private Card throneRoomKingsCourt(Game game, MoveContext context, Player current context.freeActionInEffect++; cardToPlay.cloneCount = (equals(Cards.kingsCourt) ? 3 : 2); - for (int i = 0; i < cardToPlay.cloneCount;) { - cardToPlay.numberTimesAlreadyPlayed = i++; + int cloneCount = cardToPlay.cloneCount; + cardToPlay.numberTimesAlreadyPlayed = -1; + for (int i = 0; i < cloneCount; ++i) { + cardToPlay.numberTimesAlreadyPlayed++; cardToPlay.play(game, context, cardToPlay.numberTimesAlreadyPlayed == 0 ? true : false); } diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 643af2645..931413643 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -211,9 +211,11 @@ private void royalCarriage(Card resolvedAction, MoveContext context, Game game, context.freeActionInEffect++; cardToPlay.cloneCount += 1; - cardToPlay.numberTimesAlreadyPlayed = 1; + boolean beingThroned = cardToPlay.numberTimesAlreadyPlayed > 0; + cardToPlay.numberTimesAlreadyPlayed = beingThroned ? cardToPlay.numberTimesAlreadyPlayed + 1 : 1; cardToPlay.play(game, context, false); - cardToPlay.numberTimesAlreadyPlayed = 0; //TODO: not sure if this is right + if (!beingThroned) + cardToPlay.numberTimesAlreadyPlayed = 0; //TODO: not sure if this is always right context.freeActionInEffect--; // If the cardToPlay was a knight, and was trashed, reset clonecount if (cardToPlay.isKnight() && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index a711a796a..4268471d6 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -6,6 +6,7 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; +import com.vdom.api.DurationCard; import com.vdom.api.EventCard; import com.vdom.api.GameEvent; import com.vdom.api.TreasureCard; @@ -168,12 +169,25 @@ private void bonfire(MoveContext context) { if (cards.length > 2) { Util.playerError(context.player, "Bonfire trash error, trying to trash too many cards, ignoring."); } else { + cardLoop: for (Card card : cards) { for (int i = 0; i < context.player.playedCards.size(); i++) { Card playedCard = context.player.playedCards.get(i); if (playedCard.equals(card)) { context.player.trash(context.player.playedCards.remove(i, false), this.controlCard, context); - break; + continue cardLoop; + } + } + for (int i = 0; i < context.player.nextTurnCards.size(); i++) { + Card nextTurnCard = context.player.nextTurnCards.get(i); + if (nextTurnCard.equals(card)) { + if (nextTurnCard.behaveAsCard() instanceof DurationCard) { + ((CardImpl)nextTurnCard).trashAfterPlay = true; + context.player.trash(nextTurnCard, this.controlCard, context); + } else { + context.player.trash(context.player.nextTurnCards.remove(i, false), this.controlCard, context); + } + continue cardLoop; } } } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 1ce7b5a35..dd6c05cd9 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -266,8 +266,9 @@ void start() throws ExitException { Player player = players[playersTurn]; boolean canBuyCards = extraTurnsInfo.isEmpty() ? true : extraTurnsInfo.remove().canBuyCards; MoveContext context = new MoveContext(this, player, canBuyCards); - + context.startOfTurn = true; playerBeginTurn(player, context); + context.startOfTurn = false; // ///////////////////////////////// // Actions @@ -792,7 +793,8 @@ protected void playerBeginTurn(Player player, MoveContext context) { * other Durations like Wharf - (Curse) */ boolean allDurationAreSimple = true; - ArrayList durationCards = new ArrayList(); + ArrayList durationEffects = new ArrayList(); + ArrayList durationEffectsAreCards = new ArrayList(); for (Card card : player.nextTurnCards) { Card thisCard = card.behaveAsCard(); if (thisCard instanceof DurationCard) { @@ -805,49 +807,66 @@ protected void playerBeginTurn(Player player, MoveContext context) { * that Silver), and then choose to trash a card from the second Amulet play, * now that you have more cards to choose from. */ - for (int clone = ((CardImpl) card).cloneCount; clone > 0; clone--) { + int cloneCount = ((CardImpl) card).cloneCount; + for (int clone = cloneCount; clone > 0; clone--) { if( thisCard.equals(Cards.amulet) || thisCard.equals(Cards.dungeon)) { allDurationAreSimple = false; } if(thisCard.equals(Cards.haven) || thisCard.equals(Cards.gear)) { if(player.haven != null && player.haven.size() > 0) { - durationCards.add((DurationCard) thisCard); - durationCards.add(player.haven.remove(0)); + durationEffects.add(card); + durationEffects.add(player.haven.remove(0)); + durationEffectsAreCards.add(clone == cloneCount + && !((CardImpl)card.behaveAsCard()).trashAfterPlay); + durationEffectsAreCards.add(false); } } else { - durationCards.add((DurationCard) thisCard); - durationCards.add(Cards.curse); /*dummy*/ + durationEffects.add(card); + durationEffects.add(Cards.curse); /*dummy*/ + durationEffectsAreCards.add(clone == cloneCount + && !((CardImpl)card.behaveAsCard()).trashAfterPlay); + durationEffectsAreCards.add(false); } } } else if(isModifierCard(thisCard.behaveAsCard())) { GameEvent event = new GameEvent(GameEvent.Type.PlayingDurationAction, context); - event.card = thisCard; + event.card = card; + event.newCard = true; broadcastEvent(event); } } for (Card card : player.horseTraders) { - durationCards.add(card); - durationCards.add(Cards.curse); /*dummy*/ + durationEffects.add(card); + durationEffects.add(Cards.curse); /*dummy*/ + durationEffectsAreCards.add(true); + durationEffectsAreCards.add(false); } for (Card card : player.prince) { if (!card.equals(Cards.prince)) { allDurationAreSimple = false; - durationCards.add(Cards.prince); - durationCards.add(card); + durationEffects.add(Cards.prince); + durationEffects.add(card); + durationEffectsAreCards.add(true); + durationEffectsAreCards.add(false); } } for (Card card : player.summon) { if (!card.equals(Cards.summon)) { allDurationAreSimple = false; - durationCards.add(Cards.summon); - durationCards.add(card); + durationEffects.add(Cards.summon); + durationEffects.add(card); + durationEffectsAreCards.add(true); + durationEffectsAreCards.add(false); } } while (!player.haven.isEmpty()) { /*gear could set 2 cards aside*/ - durationCards.add((DurationCard) Cards.gear); - durationCards.add(player.haven.remove(0)); + // BUG: both cards set aside by Gear need to be added to hand at the same time + durationEffects.add((DurationCard) Cards.gear); + durationEffects.add(player.haven.remove(0)); + durationEffectsAreCards.add(false); + durationEffectsAreCards.add(false); } int numOptionalItems = 0; if (!allDurationAreSimple) { @@ -864,34 +883,39 @@ protected void playerBeginTurn(Player player, MoveContext context) { if (!callableCards.isEmpty()) { Collections.sort(callableCards, new Util.CardCostComparator()); for (Card c : callableCards) { - durationCards.add(c); - durationCards.add(Cards.curse); + durationEffects.add(c); + durationEffects.add(Cards.curse); + durationEffectsAreCards.add(false); + durationEffectsAreCards.add(false); numOptionalItems += 2; } } } - while (durationCards.size() > numOptionalItems) { + while (durationEffects.size() > numOptionalItems) { int selection=0; if(allDurationAreSimple) { selection=0; } else { - selection = 2*player.controlPlayer.duration_cardToPlay(context, durationCards.toArray(new Card[durationCards.size()])); + selection = 2*player.controlPlayer.duration_cardToPlay(context, durationEffects.toArray(new Card[durationEffects.size()])); } - Card card = durationCards.get(selection); + Card card = durationEffects.get(selection); + boolean isRealCard = durationEffectsAreCards.get(selection); if (card == null) { Util.log("ERROR: duration_cardToPlay returned " + selection); selection=0; - card = durationCards.get(selection); + card = durationEffects.get(selection); } - Card card2 = durationCards.get(selection+1); + Card card2 = durationEffects.get(selection+1); if (card2 == null) { Util.log("ERROR: duration_cardToPlay returned " + selection); card2 = card; } - durationCards.remove(selection+1); - durationCards.remove(selection); + durationEffects.remove(selection+1); + durationEffects.remove(selection); + durationEffectsAreCards.remove(selection+1); + durationEffectsAreCards.remove(selection); if(card.equals(Cards.prince)) { if (!(card2 instanceof DurationCard)) { @@ -920,15 +944,16 @@ protected void playerBeginTurn(Player player, MoveContext context) { Card horseTrader = player.horseTraders.remove(0); player.hand.add(horseTrader); drawToHand(context, horseTrader, 1); - } else if(card instanceof DurationCard) { - if(card.equals(Cards.haven) || card.equals(Cards.gear)) { + } else if(card.behaveAsCard() instanceof DurationCard) { + if(card.behaveAsCard().equals(Cards.haven) || card.behaveAsCard().equals(Cards.gear)) { player.hand.add(card2); } DurationCard thisCard = (DurationCard) card.behaveAsCard(); GameEvent event = new GameEvent(GameEvent.Type.PlayingDurationAction, context); - event.card = thisCard; + event.card = card; + event.newCard = isRealCard; broadcastEvent(event); context.actions += thisCard.getAddActionsNextTurn(); @@ -1003,10 +1028,11 @@ protected void playerBeginTurn(Player player, MoveContext context) { } else { CardImpl behaveAsCard = (CardImpl) card.behaveAsCard(); behaveAsCard.cloneCount = 1; - if (!behaveAsCard.trashAfterPlay) { + if (!(behaveAsCard.trashAfterPlay || ((CardImpl)card).trashAfterPlay)) { player.playedCards.add(card); } else { behaveAsCard.trashAfterPlay = false; + ((CardImpl)card).trashAfterPlay = false; } } } @@ -1046,7 +1072,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } } - private boolean isModifierCard(Card card) { + public static boolean isModifierCard(Card card) { return card.equals(Cards.throneRoom) || card.equals(Cards.disciple) || card.equals(Cards.kingsCourt) diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index ccae9f6b6..e08b09a22 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -37,6 +37,7 @@ public class MoveContext { public int totalEventsBoughtThisTurn = 0; public int totalExpeditionBoughtThisTurn = 0; public boolean canBuyCards = true; + public boolean startOfTurn = false; public boolean buyPhase = false; public boolean blackMarketBuyPhase = false; // this is not a really buyPhase (peddler costs 8, you can't spend Guilds coin tokens) public ArrayList cantBuy = new ArrayList(); diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 3c267e7bf..118aa3e55 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; - import java.util.List; import java.util.Map; @@ -417,6 +416,8 @@ else if (cardsInPlay.get(i).isKnight()) } GameStatus gs = new GameStatus(); + + matchToCardsInPlay(context, playedCards, playedCardsNew); int[] playedArray = new int[playedCards.size()]; for (int i = 0; i < playedCards.size(); i++) { @@ -482,7 +483,53 @@ else if (cardsInPlay.get(i).isKnight()) return p; } - @Override + private void matchToCardsInPlay(MoveContext context, ArrayList played, ArrayList playedReal) { + if (context.startOfTurn) + return; + Map inPlayCounts = new HashMap(); + for (Card c : context.player.playedCards) { + if (!inPlayCounts.containsKey(c)) { + inPlayCounts.put(c, 1); + } else { + inPlayCounts.put(c, inPlayCounts.get(c)+1); + } + } + for (Card c : context.player.nextTurnCards) { + if (((CardImpl)c).trashAfterPlay) + continue; + if (!inPlayCounts.containsKey(c)) { + inPlayCounts.put(c, 1); + } else { + inPlayCounts.put(c, inPlayCounts.get(c)+1); + } + } + Map playedCounts = new HashMap(); + for (int i = 0; i < played.size(); ++i) { + if (!playedReal.get(i)) + continue; + Card c = played.get(i); + if (!playedCounts.containsKey(c)) { + playedCounts.put(c, 1); + } else { + playedCounts.put(c, playedCounts.get(c)+1); + } + } + + for (Card c : playedCounts.keySet()) { + int inPlayCount = (inPlayCounts.containsKey(c) ? inPlayCounts.get(c) : 0); + if (playedCounts.get(c) > inPlayCount) { + int extras = playedCounts.get(c) - inPlayCount; + for (int i = played.size() - 1; extras > 0 && i >= 0; --i) { + if (played.get(i).equals(c) && playedReal.get(i)) { + playedReal.set(i, false); + extras--; + } + } + } + } + } + + @Override public void newGame(MoveContext context) { hasJoinedMonitor = new Object(); // every game needs a different monitor, otherwise we wake up threads that are supposed to be dead. context.addGameListener(this); @@ -648,12 +695,6 @@ public void gameEvent(GameEvent event) { } else if (isPlayersTurn(event) && event.getType() == Type.PlayingCoin) { playedCards.add(event.getCard()); playedCardsNew.add(event.newCard); - } else if (event.getType() == Type.CardObtained) { - if (event.responsible.equals(Cards.hornOfPlenty) && event.card instanceof VictoryCard) { - int index = playedCards.indexOf(event.responsible); - playedCards.remove(index); - playedCardsNew.remove(index); - } } else if (event.getType() == Type.GameOver) { curPlayer = event.getPlayer(); curContext = context; diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 7212a70e4..96dd7822e 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -83,15 +83,16 @@ public boolean playTreasure(MoveContext context, boolean isClone) { Player player = context.player; Game game = context.game; + if (this.numberTimesAlreadyPlayed == 0) { + player.hand.remove(this); + player.playedCards.add(this); + } + GameEvent event = new GameEvent(GameEvent.Type.PlayingCoin, (MoveContext) context); event.card = this; event.newCard = !isClone; game.broadcastEvent(event); - if (this.numberTimesAlreadyPlayed == 0) { - player.hand.remove(this); - player.playedCards.add(this); - } if (isAttack()) attackPlayed(context, game, player); From 8194349e50fbdf0e3a9a8721d8cd785fa45904ac Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 18:53:31 -0700 Subject: [PATCH 052/141] Inheritance: Moved methods from ActionCard and ActionCardImpl down to Card interface. --- androminion/.classpath | 4 +-- androminion/res/values-xlarge/text_styles.xml | 30 ++++++++-------- vdom/src/com/vdom/api/ActionCard.java | 30 +--------------- vdom/src/com/vdom/api/Card.java | 21 +++++++++++ vdom/src/com/vdom/core/BasePlayer.java | 7 +++- vdom/src/com/vdom/core/CardImpl.java | 35 +++++++++++++++++++ 6 files changed, 80 insertions(+), 47 deletions(-) diff --git a/androminion/.classpath b/androminion/.classpath index d894da296..d5657aba7 100644 --- a/androminion/.classpath +++ b/androminion/.classpath @@ -3,11 +3,11 @@ - - + + diff --git a/androminion/res/values-xlarge/text_styles.xml b/androminion/res/values-xlarge/text_styles.xml index bd744092c..c217b546c 100644 --- a/androminion/res/values-xlarge/text_styles.xml +++ b/androminion/res/values-xlarge/text_styles.xml @@ -1,16 +1,16 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/vdom/src/com/vdom/api/ActionCard.java b/vdom/src/com/vdom/api/ActionCard.java index da6505c58..95ece58d6 100644 --- a/vdom/src/com/vdom/api/ActionCard.java +++ b/vdom/src/com/vdom/api/ActionCard.java @@ -1,33 +1,5 @@ package com.vdom.api; -import com.vdom.core.Game; -import com.vdom.core.MoveContext; - public interface ActionCard extends Card { - public int getAddActions(); - - public int getAddBuys(); - - public int getAddCards(); - - public int getAddGold(); - - public int getAddVictoryTokens(); - - public boolean isAttack(); - - public boolean isRuins(); - - public boolean isKnight(); - - public boolean isLooter(); - - public boolean isReserve(); - - public boolean isTraveller(); - - public boolean trashForced(); - - public void play(Game game, MoveContext context); - + } diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 4e4c39315..673250a9f 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -3,6 +3,7 @@ import java.io.Serializable; import com.vdom.core.CardImpl; +import com.vdom.core.Game; import com.vdom.core.Cards.Type; import com.vdom.core.MoveContext; @@ -48,6 +49,26 @@ public interface Card extends Serializable { public boolean isTraveller(); + public int getAddCards(); + + public int getAddActions(); + + public int getAddGold(); + + public int getAddBuys(); + + public int getAddVictoryTokens(); + + /** + * Does this card force you to trash a card when played? (Used for AI) + * @return Whether this card forces you to trash a card when played + */ + public boolean trashForced(); + + public void play(Game game, MoveContext context); + + public void play(Game game, MoveContext context, boolean fromHand); + public Integer getId(); public void isBuying(MoveContext context); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 450ddd0db..ffeef5cd4 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -1156,8 +1156,12 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis if ( !card.isRuins() && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() - && !((ActionCardImpl) card).trashOnUse && !(card instanceof DurationCard) + && !(card.isReserve()) + && !(card.isTraveller()) + && !card.equals(Cards.feast) + && !card.equals(Cards.embargo) + && !card.equals(Cards.pillage) && !card.equals(Cards.shantyTown) && !card.equals(Cards.island) && !card.equals(Cards.lookout) @@ -1165,6 +1169,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis && !card.equals(Cards.deathCart) && !card.equals(Cards.procession) && !card.equals(Cards.madman) + && !card.equals(Cards.raze) && !card.equals(Cards.prince) ) { actionCards.add(card); diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 764b74506..7894a869a 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -255,6 +255,36 @@ public boolean isVictory(MoveContext context) { return (this instanceof VictoryCard); } + @Override + public int getAddCards() { + return 0; + } + + @Override + public int getAddActions() { + return 0; + } + + @Override + public int getAddGold() { + return 0; + } + + @Override + public int getAddBuys() { + return 0; + } + + @Override + public int getAddVictoryTokens() { + return 0; + } + + @Override + public boolean trashForced() { + return false; + } + /** * @return the id */ @@ -262,8 +292,13 @@ public Integer getId() { return id; } + @Override public void play(Game game, MoveContext context) { } + + @Override + public void play(Game game, MoveContext context, boolean fromHand) { + } public String getStats() { StringBuilder sb = new StringBuilder(); From eeebaf1d1b68cfe3e1ac46a4e66765e9de4df57e Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 21:16:02 -0700 Subject: [PATCH 053/141] Inheritance: Creating isAction method on Card interface. Removing external references to ActionCardImpl by type. --- vdom/src/com/vdom/api/Card.java | 2 ++ vdom/src/com/vdom/core/ActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 6 +++++- vdom/src/com/vdom/core/Player.java | 12 +++++++++--- vdom/src/com/vdom/players/VDomPlayerPatrick.java | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 673250a9f..324a77833 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -29,6 +29,8 @@ public interface Card extends Serializable { public boolean costPotion(); + public boolean isAction(); + public boolean isAttack(); public boolean isPrize(); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 47b7f43f2..fb4743de1 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -306,7 +306,7 @@ private boolean isInPlay(Player currentPlayer) { return true; } for (Card c : currentPlayer.nextTurnCards) { - if (c instanceof ActionCardImpl && !((ActionCardImpl)c).trashAfterPlay && this == c) + if (c instanceof CardImpl && !((CardImpl)c).trashAfterPlay && this == c) if (this == c) return true; } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 7894a869a..7925f100f 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -232,7 +232,7 @@ public int getCost(MoveContext context, boolean buyPhase) { return context.game.getTopKnightCard().getCost(context,buyPhase); int costModifier = 0; - costModifier -= (this instanceof ActionCardImpl) ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; + costModifier -= this.isAction() ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; costModifier -= context.countCardsInPlay(Cards.highway); costModifier -= context.countCardsInPlay(Cards.bridgeTroll); costModifier -= context.countCardsInNextTurn(Cards.bridgeTroll); @@ -336,6 +336,10 @@ public boolean costPotion() { return costPotion; } + public boolean isAction() { + return this instanceof ActionCard; + } + @Override public boolean isAttack() { return isAttack; diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 7ca615b75..d19f6c6d7 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -116,7 +116,7 @@ public void newTurn() { public ArrayList getActionCards(Card[] cards) { ArrayList actionCards = new ArrayList(); for (Card card : cards) { - if (card instanceof ActionCardImpl) { + if (card.isAction()) { actionCards.add(card); } } @@ -736,11 +736,17 @@ public int getCardCount(final Class cardClass, ArrayList cards) { } public int getActionCardCount() { - return this.getCardCount(ActionCard.class); + return getActionCardCount(getAllCards()); } public int getActionCardCount(ArrayList cards) { - return this.getCardCount(ActionCard.class, cards); + int cardCount = 0; + for (Card c : cards) { + if (c.isAction()) { + cardCount++; + } + } + return cardCount; } public int getVictoryCardCount() { diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index ba77eb08c..c13d8eff4 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -659,7 +659,7 @@ private int getVPTotalValue (ArrayList list) { vps += list.size() / 10; } if (card.equals(Cards.vineyard)) { - vps += Math.round(this.getCardCount(ActionCard.class, list) / 3); + vps += Math.round(this.getActionCardCount(list) / 3); } if (card.equals(Cards.fairgrounds)) { vps += Math.round(this.getCardNameCount(list) / 5); From 6adb27dfd2a5a7a8053289c56b9b79ba899bf5a5 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 21:18:49 -0700 Subject: [PATCH 054/141] Reverting classpath. --- androminion/.classpath | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/androminion/.classpath b/androminion/.classpath index d5657aba7..d894da296 100644 --- a/androminion/.classpath +++ b/androminion/.classpath @@ -3,11 +3,11 @@ + - - + From f03bdeddd736ac71a1aa273e3555ccf09887184c Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 22:15:32 -0700 Subject: [PATCH 055/141] Inheritance: removing references to instanceof ActionCard. --- vdom/src/com/vdom/api/Card.java | 8 ++ .../src/com/vdom/comms/SelectCardOptions.java | 8 +- vdom/src/com/vdom/core/ActionCardImpl.java | 36 ++++----- vdom/src/com/vdom/core/BasePlayer.java | 73 ++++++++++--------- .../com/vdom/core/CallableActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 5 ++ vdom/src/com/vdom/core/Game.java | 6 +- vdom/src/com/vdom/core/IndirectPlayer.java | 2 +- vdom/src/com/vdom/core/MoveContext.java | 8 +- vdom/src/com/vdom/core/Player.java | 14 ++-- vdom/src/com/vdom/core/QuickPlayPlayer.java | 2 +- vdom/src/com/vdom/core/Util.java | 6 +- vdom/src/com/vdom/core/VariableCardPile.java | 11 +-- .../src/com/vdom/players/VDomPlayerChuck.java | 4 +- vdom/src/com/vdom/players/VDomPlayerEarl.java | 12 +-- .../com/vdom/players/VDomPlayerPatrick.java | 20 ++--- .../src/com/vdom/players/VDomPlayerSarah.java | 4 +- 17 files changed, 116 insertions(+), 105 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 324a77833..be09677e7 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -6,6 +6,7 @@ import com.vdom.core.Game; import com.vdom.core.Cards.Type; import com.vdom.core.MoveContext; +import com.vdom.core.Player; public interface Card extends Serializable { @@ -31,6 +32,13 @@ public interface Card extends Serializable { public boolean isAction(); + /** + * Is the card an action if it belonged to the current player? + * @param player + * @return + */ + public boolean isAction(Player player); + public boolean isAttack(); public boolean isPrize(); diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index 36bdad562..2c0ccfe84 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -156,7 +156,7 @@ public boolean checkValid(MyCard c) { /* Note: This method must be synchrony with checkValid(Card c, int cost, boolean cardIsVictory) */ public boolean checkValid(MyCard c, int cost) { - if ((maxCost >= 0) && (cost > (c.costPotion ? maxCost : maxCostWithoutPotion))) return false; + /* if ((maxCost >= 0) && (cost > (c.costPotion ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; if (isAction && !c.isAction) return false; @@ -172,7 +172,7 @@ public boolean checkValid(MyCard c, int cost) { if (fromTable && !fromPrizes && c.isPrize) return false; //if (fromPrizes && !c.isPrize && !fromTable) return false; if (potionCost == 0 && c.costPotion) return false; - if (maxCost == minCost && potionCost > 0 && !c.costPotion) return false; + if (maxCost == minCost && potionCost > 0 && !c.costPotion) return false; */ if (!cardInList(c.id)) return false; return true; @@ -201,10 +201,8 @@ public boolean checkValid(Card c, int cost, boolean cardIsVictory) { if (c.equals(Cards.grandMarket) && copperCountInPlay > 0) return false; if (isNonShelter && c.isShelter()) return false; if (isAttack && !c.isAttack()) return false; + if (isAction && !c.isAction()) return false; - if (!(c instanceof ActionCard)) { - if (isAction) return false; - } if (isBuyPhase && !Cards.isSupplyCard(c) && !c.isEvent()) return false; if (isSupplyCard && !Cards.isSupplyCard(c)) return false; diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index fb4743de1..57cc6f272 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1151,7 +1151,7 @@ private void prince(Game game, MoveContext context, Player currentPlayer) { card = null; } - if (card != null && card instanceof ActionCard && card.getCost(context) <= 4 && !card.costPotion()) { + if (card != null && card.isAction() && card.getCost(context) <= 4 && !card.costPotion()) { currentPlayer.prince.add(currentPlayer.playedCards.remove(currentPlayer.playedCards.lastIndexOf((Card) this.controlCard))); this.controlCard.stopImpersonatingCard(); @@ -1327,7 +1327,7 @@ private void mine(MoveContext context, Player currentPlayer) { private void university(MoveContext context, Player currentPlayer) { ActionCard cardToObtain = currentPlayer.controlPlayer.university_actionCardToObtain(context); - if (cardToObtain != null && cardToObtain instanceof ActionCard && cardToObtain.getCost(context) <= 5 && !cardToObtain.costPotion()) { + if (cardToObtain != null && cardToObtain.isAction() && cardToObtain.getCost(context) <= 5 && !cardToObtain.costPotion()) { currentPlayer.gainNewCard(cardToObtain, this.controlCard, context); } } @@ -1358,7 +1358,7 @@ private void transmute(MoveContext context, Player currentPlayer) { } else { currentPlayer.hand.remove(cardToTrash); currentPlayer.trash(cardToTrash, this.controlCard, context); - if (cardToTrash instanceof ActionCard) { + if (cardToTrash.isAction()) { currentPlayer.gainNewCard(Cards.duchy, this.controlCard, context); } if (cardToTrash instanceof TreasureCard) { @@ -1797,7 +1797,7 @@ private Card throneRoomKingsCourt(Game game, MoveContext context, Player current ArrayList actionCards = new ArrayList(); ActionCardImpl cardToPlay = null; for (Card card : currentPlayer.hand) { - if (card instanceof ActionCard) { + if (card.isAction()) { actionCards.add(card); } } @@ -1929,7 +1929,7 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { if (card != null) { player.reveal(card, this.controlCard, playerContext); - if (card instanceof TreasureCard || card instanceof ActionCard) { + if (card instanceof TreasureCard || card.isAction()) { cardToDiscard.add(card); } else { topOfTheDeck.add(card); @@ -2063,7 +2063,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(context, controlCard, -1)) != null && !(draw instanceof ActionCard) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(context, controlCard, -1)) != null && !(draw.isAction()) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -3047,7 +3047,7 @@ private void shantyTown(Game game, MoveContext context, Player currentPlayer) { for (Card card : currentPlayer.hand) { currentPlayer.reveal(card, this.controlCard, context); - if (card instanceof ActionCard) { + if (card.isAction()) { actions = true; } } @@ -3133,7 +3133,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla while ((draw = game.draw(context, controlCard, -1)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); - if(!(draw instanceof ActionCard)) { + if(!(draw.isAction())) { break; } } @@ -3207,7 +3207,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { Card card = currentPlayer.controlPlayer.ironworks_cardToObtain(context); if (card != null && card.getCost(context) <= 4 && !card.costPotion()) { if (currentPlayer.gainNewCard(card, this.controlCard, context).equals(card)) { - if (card instanceof ActionCard) { + if (card.isAction()) { context.actions++; } if (card instanceof TreasureCard) { @@ -3259,7 +3259,7 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { for (Card card : revealedCards) { if (card != null && !card.equals(Cards.curse)) { - if (card instanceof ActionCard) { + if (card.isAction()) { context.actions += 2; } if (card instanceof TreasureCard) { @@ -3775,7 +3775,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { currentPlayer.reveal(draw, this.controlCard, context); - if (draw instanceof ActionCard && !draw.equals(Cards.golem)) { + if (draw.isAction() && !draw.equals(Cards.golem)) { toOrder.add(draw); // currentPlayer.hand.add(draw); } else { @@ -3860,7 +3860,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { } boolean shouldKeep = true; - if (draw instanceof ActionCard) { + if (draw.isAction()) { shouldKeep = currentPlayer.controlPlayer.library_shouldKeepAction(context, (ActionCard) draw); } @@ -4627,7 +4627,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { case TrashActionCard: Card toTrash = currentPlayer.controlPlayer.graverobber_cardToTrash(context); - if (toTrash == null || !currentPlayer.hand.contains(toTrash) || !(toTrash instanceof ActionCard)) { + if (toTrash == null || !currentPlayer.hand.contains(toTrash) || !(toTrash.isAction())) { Util.playerError(currentPlayer, "Graverobber trash error, trashing nothing."); return; } @@ -4655,7 +4655,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { currentPlayer.putOnTopOfDeck(card, context, true); } - if (card instanceof ActionCard) { + if (card.isAction()) { context.actions += 1; } if (card instanceof TreasureCard) { @@ -4793,7 +4793,7 @@ private void wanderingMinstrel(Player currentPlayer, MoveContext context) { if (card == null) { break; } - if (!(card instanceof ActionCard) ) { + if (!(card.isAction()) ) { currentPlayer.discard(card, this.controlCard, context); } else { currentPlayer.reveal(card, this.controlCard, context); @@ -5582,7 +5582,7 @@ private void bandOfMisfits(Game game, MoveContext context, Player currentPlayer) if (cardToImpersonate != null && !game.isPileEmpty(cardToImpersonate) && Cards.isSupplyCard(cardToImpersonate) - && cardToImpersonate instanceof ActionCard + && cardToImpersonate.isAction() && cardToImpersonate.getCost(context) < this.controlCard.getCost(context) && (context.golemInEffect == 0 || cardToImpersonate != Cards.golem)) { GameEvent event = new GameEvent(GameEvent.Type.CardNamed, (MoveContext) context); @@ -6032,7 +6032,7 @@ private void herald(Game game, MoveContext context, Player currentPlayer) { currentPlayer.reveal(draw, this.controlCard, context); - if (draw instanceof ActionCard) + if (draw.isAction()) { context.freeActionInEffect++; ((ActionCardImpl) draw).play(game, context, false); @@ -6271,7 +6271,7 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) } else { currentPlayer.putOnTopOfDeck(c, context, true); } - if ((c instanceof VictoryCard) || (c instanceof ActionCard)) { + if ((c instanceof VictoryCard) || (c.isAction())) { currentPlayer.gainNewCard(Cards.magpie, this.controlCard, context); } } diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index ffeef5cd4..49f28bb64 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -56,7 +56,7 @@ public void gameEvent(GameEvent event) { reactedSet.clear(); } if(event.getPlayer() == this && (event.getType() == GameEvent.Type.CardObtained || event.getType() == GameEvent.Type.BuyingCard)) { - if(event.getCard() instanceof ActionCard) { + if(event.getCard().isAction()) { actionCardCount++; } @@ -193,7 +193,7 @@ protected Card bestCardInPlay(MoveContext context, int maxCost, boolean exactCos || card.equals(Cards.ruinedVillage) || card.equals(Cards.survivors) || !Cards.isSupplyCard(card) - || (actionOnly && !(card instanceof ActionCard)) + || (actionOnly && !(card.isAction(this))) || (!victoryCardAllowed && (card instanceof VictoryCard) && !card.equals(Cards.curse)) ) { /*card not allowed*/ @@ -557,7 +557,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { int bestAction = -1; boolean removed = false; for (int i = 0; i < keepers.size(); i++) { - if (keepers.get(i) instanceof ActionCard) { + if (keepers.get(i).isAction()) { if (bestAction == -1) { bestAction = i; } else { @@ -677,10 +677,10 @@ public Card[] chapel_cardsToTrash(MoveContext context) { public Card[] cellar_cardsToDiscard(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (context.getActionsLeft() == 0 && card instanceof ActionCard) { + if (context.getActionsLeft() == 0 && card.isAction()) { cards.add(card); } - else if ((!(card instanceof ActionCard) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.copper)) { + else if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.copper)) { cards.add(card); } else if (shouldDiscard(card)) { @@ -700,7 +700,7 @@ public boolean library_shouldKeepAction(MoveContext context, ActionCard action) return false; } for (Card card : context.getPlayer().getHand()) { - if (card instanceof ActionCard && !card.isRuins()) { + if (card.isAction() && !card.isRuins()) { return false; } } @@ -949,7 +949,7 @@ public NoblesOption nobles_chooseOptions(MoveContext context) { int actionCards = 0; for (Card card : context.getPlayer().getHand()) { - if ((card instanceof ActionCard)) { + if ((card.isAction())) { actionCards++; } } @@ -1152,7 +1152,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis ArrayList randList = new ArrayList(); int maxCost = -1; for (Card card : cardList) { - if (card instanceof ActionCard && card.getCost(context) <= 4 && !card.costPotion()) { + if (card.isAction() && card.getCost(context) <= 4 && !card.costPotion()) { if ( !card.isRuins() && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() @@ -1522,7 +1522,7 @@ public Card contraband_cardPlayerCantBuy(MoveContext context) { public ActionCard kingsCourt_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { - if(c instanceof ActionCard) { + if(c.isAction()) { return (ActionCard) c; } } @@ -1650,7 +1650,7 @@ public ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards) { public Card hamlet_cardToDiscardForAction(MoveContext context) { int actionCards = 0; for (Card c : context.getPlayer().getHand()) { - if(c instanceof ActionCard) { + if(c.isAction()) { actionCards++; } } @@ -1783,7 +1783,7 @@ public VictoryCard bureaucrat_cardToReplace(MoveContext context) { int actions = 0; for (Card card : cards) { - if (card instanceof ActionCard) { + if (card.isAction()) { actions++; } } @@ -1883,7 +1883,7 @@ public boolean isOnlyTreasure(Card card) { return false; } - if(card instanceof ActionCard || card instanceof VictoryCard) { + if(card.isAction() || card instanceof VictoryCard) { return false; } @@ -1905,7 +1905,7 @@ public boolean isOnlyVictory(Card card) { return false; } - if(card instanceof ActionCard || card instanceof TreasureCard) { + if(card.isAction() || card instanceof TreasureCard) { return false; } @@ -2219,7 +2219,7 @@ public TreasureCard stables_treasureToDiscard(MoveContext context) { public Card mandarin_cardToReplace(MoveContext context) { if (context.getActionsLeft() == 0) { for (Card card : context.getPlayer().getHand()) { - if (card instanceof ActionCard) { + if (card.isAction()) { return card; } } @@ -2371,16 +2371,19 @@ public Card forager_cardToTrash(MoveContext context) { @Override public Card deathCart_actionToTrash(MoveContext context) { - Card ac = null; for (Card c : context.player.hand) { - if (c instanceof ActionCard) - { - ac = c; - break; + if (c.isRuins()) { + return c; } } - return ac; + for (Card c : context.player.hand) + { + if (c.isAction() && c.getCost(context) <= Cards.deathCart.getCost(context)) { + return c; + } + } + return null; } @Override @@ -2417,7 +2420,7 @@ public Card graverobber_cardToGainFromTrash(MoveContext context) { public Card graverobber_cardToTrash(MoveContext context) { CardList ac = new CardList(controlPlayer, getPlayerName(false)); for (Card c : hand) { - if (c instanceof ActionCard) { + if (c.isAction()) { ac.add(c); } } @@ -2489,14 +2492,14 @@ public Card scavenger_cardToPutBackOnDeck(MoveContext context) { public Card[] storeroom_cardsToDiscardForCards(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if ((!(card instanceof ActionCard) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { + if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { cards.add(card); } } if (context.getActionsLeft() == 0) { for (Card c : context.getPlayer().getHand()) { - if ((c instanceof ActionCard)) { + if ((c.isAction())) { cards.add(c); } } @@ -2509,14 +2512,14 @@ public Card[] storeroom_cardsToDiscardForCards(MoveContext context) { public Card[] storeroom_cardsToDiscardForCoins(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if ((!(card instanceof ActionCard) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { + if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { cards.add(card); } } if (context.getActionsLeft() == 0) { for (Card c : context.getPlayer().getHand()) { - if ((c instanceof ActionCard)) { + if ((c.isAction())) { cards.add(c); } } @@ -2608,7 +2611,7 @@ public Card pillage_opponentCardToDiscard(MoveContext context, ArrayList h ArrayList goodCards = new ArrayList(); for (Card c : handCards) - if (c instanceof TreasureCard || c instanceof ActionCard) + if (c instanceof TreasureCard || c.isAction()) goodCards.add(c); if (goodCards.size() > 0) { @@ -2649,7 +2652,7 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { boolean containsCopper = false; CardList cl = new CardList(context.getPlayer(), context.getPlayer().getPlayerName()); for(Card card : cards) { - if (!isOnlyVictory(card) && !isCurse(card) && !isTrashCard(card) && !(context.actions == 0 && (card instanceof ActionCard))) { + if (!isOnlyVictory(card) && !isCurse(card) && !isTrashCard(card) && !(context.actions == 0 && (card.isAction()))) { cl.add(card); } if (card.equals(Cards.copper)) { @@ -2781,7 +2784,7 @@ public Card[] urchin_attack_cardsToKeep(MoveContext context) int bestAction = -1; boolean removed = false; for (int i = 0; i < keepers.size(); i++) { - if (keepers.get(i) instanceof ActionCard) { + if (keepers.get(i).isAction()) { if (bestAction == -1) { bestAction = i; } else { @@ -2864,7 +2867,7 @@ public Card hermit_cardToTrash(MoveContext context, ArrayList cardList, in { CardList cl = new CardList(controlPlayer, getPlayerName(false)); for (Card c : cardList) { - if (c instanceof ActionCard) { + if (c.isAction()) { cl.add(c); } } @@ -3252,7 +3255,7 @@ public CallableCard call_whenActionResolveCardToCall(MoveContext context, Action // Check coin of the Realm first boolean hasMoreActionsLeft = false; for (Card c : getHand()) { - if (c instanceof ActionCard) { + if (c.isAction()) { hasMoreActionsLeft = true; } } @@ -3342,7 +3345,7 @@ private Card getBestActionCard(CardList hand, MoveContext context) { int highestCost = -1; Card bestCard = null; for (Card c : getDistinctCards()) { - if (c instanceof ActionCard) { + if (c.isAction()) { int cost = c.getCost(context); if (cost > highestCost) { highestCost = cost; @@ -3357,7 +3360,7 @@ private Card getBestActionCard(CardList hand, MoveContext context) { public ActionCard disciple_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { - if(c instanceof ActionCard) { + if(c.isAction()) { return (ActionCard) c; } } @@ -3373,7 +3376,7 @@ public Card fugitive_cardToDiscard(MoveContext context) { public Card[] gear_cardsToSetAside(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (context.getActionsLeft() == 0 && card instanceof ActionCard) { + if (context.getActionsLeft() == 0 && card.isAction()) { cards.add(card); } } @@ -3477,7 +3480,7 @@ public Card raze_cardToKeep(MoveContext context, Card[] cards) { ArrayList goodCards = new ArrayList(); for (Card c : cards) - if (c instanceof TreasureCard || c instanceof ActionCard) + if (c instanceof TreasureCard || c.isAction()) goodCards.add(c); if (goodCards.size() > 0) { @@ -3531,7 +3534,7 @@ public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerS Card[] cards = context.game.getCardsInGame(); Arrays.sort(cards, new Util.CardCostComparatorDesc()); for (Card c : cards) { - if (c instanceof ActionCard && + if (c.isAction() && Cards.isSupplyCard(c) && game.getPlayerSupplyTokens(c, this).size() == 0) return (ActionCard) c; diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 931413643..784607071 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -243,7 +243,7 @@ private void teacher(MoveContext context, Game game, Player currentPlayer) { ActionCard lastFreePile = null; for (Card c : game.getCardsInGame()) { if (game.getPile(c).isSupply() - && c instanceof ActionCard + && c.isAction() && game.getPlayerSupplyTokens(c, currentPlayer).size() == 0) { numFreePiles++; lastFreePile = (ActionCard) c; diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 7925f100f..2b4501d5b 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -340,6 +340,11 @@ public boolean isAction() { return this instanceof ActionCard; } + @Override + public boolean isAction(Player player) { + return player.getInheritance() != null && this.getType() == player.getInheritance().getType(); + } + @Override public boolean isAttack() { return isAttack; diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index dd6c05cd9..4f458fe02 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1430,7 +1430,7 @@ public boolean isValidAction(MoveContext context, Card action) { return false; } - if (!(action instanceof ActionCard)) { + if (!(action.isAction())) { return false; } @@ -2352,7 +2352,7 @@ protected void initCards() { // We have to add one "invisible" pile for each ruins card and a "virtual" visible pile boolean looter = false; for (AbstractCardPile pile : piles.values()) { - if (pile.card() instanceof ActionCard && ((ActionCard)pile.card()).isLooter()) { + if (pile.card().isLooter()) { looter = true; } } @@ -2708,7 +2708,7 @@ public void gameEvent(GameEvent event) { int actionCardsFound = 0; for(int i=player.discard.size() - 1; i >= 0; i--) { Card c = player.discard.get(i); - if(c instanceof ActionCard) { + if(c.isAction()) { actionCardsFound++; if(player.controlPlayer.inn_shuffleCardBackIntoDeck(event.getContext(), (ActionCard) c)) { cards.add(c); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 25ca82c43..06f5e2796 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -219,7 +219,7 @@ private Card[] doAction(MoveContext context, boolean singleCard) { int actionCount = 0; Card actionCard = null; for (Card card : (context.player.isPossessed()) ? context.player.getHand() : getHand()) { - if (card instanceof ActionCard) { + if (card.isAction()) { actionCount++; actionCard = card; } diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index e08b09a22..66ec7fb67 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -166,7 +166,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { for (Card c : getPlayedCards()) { if ((type == CardsInPlay.ATTACK && c.isAttack()) || (type == CardsInPlay.TRAVELLER && c.isTraveller()) - || (type == CardsInPlay.ACTION && c.behaveAsCard() instanceof ActionCard)) { + || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; } } @@ -175,7 +175,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { continue; if ((type == CardsInPlay.ATTACK && c.isAttack()) || (type == CardsInPlay.TRAVELLER && c.isTraveller()) - || (type == CardsInPlay.ACTION && c.behaveAsCard() instanceof ActionCard)) { + || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; } } @@ -282,8 +282,8 @@ public GameType getGameType() { } public boolean canPlay(Card card) { - if (card instanceof ActionCard) { - return game.isValidAction(this, (ActionCard) card); + if (card.isAction()) { + return game.isValidAction(this, card); } else { return false; } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index d19f6c6d7..cf5c0bbcc 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -131,7 +131,7 @@ public int getActionCardCount(Card[] cards) { public int getMyAddActionCardCount() { int addActionsCards = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { if (((ActionCard) card).getAddActions() > 0) { addActionsCards++; } @@ -144,7 +144,7 @@ public int getMyAddActionCardCount() { public int getMyAddCardCardCount() { int addCards = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { if (((ActionCard) card).getAddCards() > 0) { addCards++; } @@ -157,7 +157,7 @@ public int getMyAddCardCardCount() { public int getMyAddActions() { int addActions = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { addActions += ((ActionCard) card).getAddActions(); } } @@ -168,7 +168,7 @@ public int getMyAddActions() { public int getMyAddCards() { int addCards = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { addCards += ((ActionCard) card).getAddCards(); } } @@ -179,7 +179,7 @@ public int getMyAddCards() { public int getMyAddBuys() { int addBuys = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { addBuys += ((ActionCard) card).getAddBuys(); } } @@ -396,7 +396,7 @@ protected void cleanup(MoveContext context) { context.schemesPlayed --; ArrayList actions = new ArrayList(); for(Card c : playedCards) { - if(c instanceof ActionCard) { + if(c.isAction()) { actions.add(c); } } @@ -1404,7 +1404,7 @@ public ArrayList getActionsInHand() { ArrayList actions = new ArrayList(); for (Card c : getHand()) - if (c instanceof ActionCard) + if (c.isAction()) actions.add((ActionCard) c); return actions; diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 1c6933a14..dc4983f42 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -493,7 +493,7 @@ public boolean shouldAutoPlay_hamlet_cardToDiscardForAction(MoveContext context) int actionCards = 0; int trashCards = 0; for(Card c : getHand()) { - if(c instanceof ActionCard) { + if(c.isAction()) { actionCards++; } for(Card trash : getTrashCards()) { diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index f56713a6e..b82a50b61 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -650,13 +650,13 @@ public int compare(Card card0, Card card1) { static public class CardTypeComparator implements Comparator { @Override public int compare(Card card0, Card card1) { - if(card0 instanceof ActionCard) { - if(card1 instanceof ActionCard) { + if(card0.isAction()) { + if(card1.isAction()) { return 0; } else { return -1; } - } else if(card1 instanceof ActionCard) { + } else if(card1.isAction()) { return 1; } else if(card0 instanceof TreasureCard || card0.getType() == Type.Potion) { if(card1 instanceof TreasureCard || card1.getType() == Type.Potion) { diff --git a/vdom/src/com/vdom/core/VariableCardPile.java b/vdom/src/com/vdom/core/VariableCardPile.java index 973bc7f55..3ffed9871 100644 --- a/vdom/src/com/vdom/core/VariableCardPile.java +++ b/vdom/src/com/vdom/core/VariableCardPile.java @@ -56,21 +56,18 @@ public void addLinkedPile(SingleCardPile p) { @Override public void addCard(Card card) { - ActionCard ac = null; - if (card instanceof ActionCard) { - ac = (ActionCard) card; - } else return; - + if (!card.isAction()) return; + piles.get(card.getName()).addCard(card); switch (type) { case KnightsPile: - if (ac.isKnight()) { + if (card.isKnight()) { cards.add(0, card); } break; case RuinsPile: - if (ac.isRuins()) { + if (card.isRuins()) { cards.add(0, card); } break; diff --git a/vdom/src/com/vdom/players/VDomPlayerChuck.java b/vdom/src/com/vdom/players/VDomPlayerChuck.java index 6261ce160..014c7a429 100644 --- a/vdom/src/com/vdom/players/VDomPlayerChuck.java +++ b/vdom/src/com/vdom/players/VDomPlayerChuck.java @@ -216,12 +216,12 @@ public Card doBuy(MoveContext context) { card.equals(Cards.throneRoom) && throneRoomAndKingsCourtCount >= 2 || card.equals(Cards.disciple) && throneRoomAndKingsCourtCount >= 2 || card.equals(Cards.kingsCourt) && throneRoomAndKingsCourtCount >= 2 || - !(card instanceof ActionCard) && !(card instanceof TreasureCard) + !(card.isAction()) && !(card instanceof TreasureCard) ) { continue; } - if (card instanceof ActionCard && actionCardCount >= ACTION_CARDS_MAX) { + if (card.isAction() && actionCardCount >= ACTION_CARDS_MAX) { continue; } diff --git a/vdom/src/com/vdom/players/VDomPlayerEarl.java b/vdom/src/com/vdom/players/VDomPlayerEarl.java index 951c15d44..05626b543 100644 --- a/vdom/src/com/vdom/players/VDomPlayerEarl.java +++ b/vdom/src/com/vdom/players/VDomPlayerEarl.java @@ -161,7 +161,7 @@ private void calculateStats(ArrayList historyItems) { HashMap victoryHelpers = getVictoryStat(historyItems); for (HistoryItem historyItem : historyItems) { - if ((historyItem.getAction() == HistoryItem.Action.BOUGHT) && (historyItem.getCard() instanceof ActionCard)) { + if ((historyItem.getAction() == HistoryItem.Action.BOUGHT) && (historyItem.getCard().isAction())) { debug(historyItem.toString() + ", was in hand " + inHand.get(historyItem.getCard().getId()) + " times, played " + played.get(historyItem.getCard().getId()) + " times, and saw " + victoryHelpers.get(historyItem.getCard().getId()) + " vps"); } @@ -211,7 +211,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe int actionCards = 0; for (Card card : hand) { - if ( card instanceof ActionCard + if ( card.isAction() && !card.equals(Cards.rats) && !(card.equals(Cards.tactician) && context.countCardsInPlay(Cards.tactician) > 0) ) { @@ -320,7 +320,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe if (card.equals(Cards.treasureMap)) { continue; } - if (card instanceof ActionCard) { + if (card.isAction()) { if (dontPlay.contains(card)) { continue; } @@ -339,7 +339,7 @@ private ActionCard getBestAddActionAction(Card[] hand) { int bestAddActions = 0; for (Card card : hand) { - if (card instanceof ActionCard) { + if (card.isAction()) { ActionCard action = (ActionCard)card; if (action.getAddActions() > 0) { int addCards = action.getAddCards(); @@ -362,7 +362,7 @@ private ActionCard getBestAddActionCard(Card[] hand) { int bestAddCards = 0; for (Card card : hand) { - if (card instanceof ActionCard) { + if (card.isAction()) { ActionCard action = (ActionCard)card; int thisAddCards = action.getAddCards(); if (thisAddCards > bestAddCards) { @@ -1004,7 +1004,7 @@ private int nonNobleActionCardCount() { if (card.equals(Cards.nobles)) { continue; } - if (card instanceof ActionCard) { + if (card.isAction()) { ++count; } } diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index c13d8eff4..ec1ca9721 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -575,7 +575,7 @@ private int getCurrencyTotal(ArrayList list) { money += (list.size()-7) / 5; } - if (card instanceof ActionCard) { + if (card.isAction()) { money += ((ActionCard) card).getAddGold(); } } @@ -604,7 +604,7 @@ private int guessCurrencyTotal(ArrayList list) { if (card instanceof TreasureCard) { money += ((TreasureCard) card).getValue(); } - if (card instanceof ActionCard) { + if (card.isAction()) { ActionCard ac = (ActionCard)card; money += ac.getAddGold(); //money += ac.getAddCards(); @@ -760,7 +760,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { switch (this.strategy) { case NoAction: for (Card card : list) { - if (card instanceof ActionCard) { + if (card.isAction()) { return card; } } @@ -820,7 +820,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { // Action cards for (Card card : list) { - if (card instanceof ActionCard) { + if (card.isAction()) { return card; } } @@ -1049,7 +1049,7 @@ public Card[] vault_cardsToDiscardForGold(MoveContext context) { while (ret.size() < 2) { if (getMyAddActions() == 0) { for (Card acard : temphand) { - if (acard instanceof ActionCard) { + if (acard.isAction()) { ret.add(acard); } } @@ -1950,7 +1950,7 @@ private int getDeckSize(ArrayList deck) { int size = 0; for (Card card : deck) { size++; - if (card instanceof ActionCard) { + if (card.isAction()) { if(isCantrip((ActionCard) card)) { size--; } @@ -2021,7 +2021,7 @@ public void gameEvent(GameEvent event) { if ((event.getType() == GameEvent.Type.BuyingCard) || (event.getType() == GameEvent.Type.CardObtained)) { Card card = event.getCard(); - if (card instanceof ActionCard) { + if (card.isAction()) { ActionCard ac = (ActionCard) card; this.opponents.get(event.player.playerNumber).putActionCard(card); if (ac.isAttack()) { @@ -2344,7 +2344,7 @@ private ArrayList getTerminalsInDeck(MoveContext context) { ArrayList ret = new ArrayList(); for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { if (((ActionCard) card).getAddActions() <= 0) { ret.add(card); } @@ -2358,7 +2358,7 @@ private float getCardsPerHand(MoveContext context) { int addcards = 0; for (Card card : getAllCards()) { - if (card instanceof ActionCard) { + if (card.isAction()) { addcards += ((ActionCard) card).getAddCards(); } } @@ -2381,7 +2381,7 @@ private Card advisorPlayAction(ArrayList hand) { this.log("advisorPlayAction: " + hand); ArrayList ac = new ArrayList(); for (Card card : hand) { - if (card instanceof ActionCard) { + if (card.isAction()) { ac.add((ActionCard) card); } } diff --git a/vdom/src/com/vdom/players/VDomPlayerSarah.java b/vdom/src/com/vdom/players/VDomPlayerSarah.java index da0788e70..b59d053a5 100644 --- a/vdom/src/com/vdom/players/VDomPlayerSarah.java +++ b/vdom/src/com/vdom/players/VDomPlayerSarah.java @@ -479,7 +479,7 @@ public Card doAction(MoveContext context) { public boolean shouldPassOnBuy(MoveContext context, Card card) { return !context.canBuy(card) || - card instanceof ActionCard && actionCardCount >= actionCardMax || + card.isAction() && actionCardCount >= actionCardMax || !favorSilverGoldPlat && (card.equals(Cards.silver) || card.equals(Cards.masterpiece) || card.equals(Cards.gold) || card.equals(Cards.platinum)) || card.equals(Cards.curse) || card.equals(Cards.virtualRuins) || @@ -490,7 +490,7 @@ public boolean shouldPassOnBuy(MoveContext context, Card card) { card.equals(Cards.disciple) && throneRoomAndKingsCourtCount >= throneRoomsAndKingsCourtsMax || card.equals(Cards.kingsCourt) && throneRoomAndKingsCourtCount >= throneRoomsAndKingsCourtsMax || context.getEmbargosIfCursesLeft(card) > 0 || - !(card instanceof ActionCard) && !(card instanceof TreasureCard) && !(card instanceof EventCard); + !(card.isAction()) && !(card instanceof TreasureCard) && !(card instanceof EventCard); } @Override From fb93beade1c0073b996aecdb5970c83cd89e8670 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 22:25:38 -0700 Subject: [PATCH 056/141] Inheritance: Moving duration card methods to Card interface. --- vdom/src/com/vdom/api/Card.java | 14 +++++++++ vdom/src/com/vdom/api/DurationCard.java | 12 -------- vdom/src/com/vdom/core/CardImpl.java | 38 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index be09677e7..2ec80ef9d 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -39,6 +39,8 @@ public interface Card extends Serializable { */ public boolean isAction(Player player); + public boolean isDuration(Player player); + public boolean isAttack(); public boolean isPrize(); @@ -69,6 +71,18 @@ public interface Card extends Serializable { public int getAddVictoryTokens(); + public int getAddCardsNextTurn(); + + public int getAddActionsNextTurn(); + + public int getAddGoldNextTurn(); + + public int getAddBuysNextTurn(); + + public boolean takeAnotherTurn(); + + public int takeAnotherTurnCardCount(); + /** * Does this card force you to trash a card when played? (Used for AI) * @return Whether this card forces you to trash a card when played diff --git a/vdom/src/com/vdom/api/DurationCard.java b/vdom/src/com/vdom/api/DurationCard.java index a51f1ed53..e7ebb51b9 100644 --- a/vdom/src/com/vdom/api/DurationCard.java +++ b/vdom/src/com/vdom/api/DurationCard.java @@ -2,16 +2,4 @@ public interface DurationCard extends ActionCard { - public int getAddActionsNextTurn(); - - public int getAddBuysNextTurn(); - - public int getAddGoldNextTurn(); - - public int getAddCardsNextTurn(); - - public boolean takeAnotherTurn(); - - public int takeAnotherTurnCardCount(); - } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 2b4501d5b..58e0b5770 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -2,6 +2,7 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; +import com.vdom.api.DurationCard; import com.vdom.api.VictoryCard; public class CardImpl implements Card { @@ -280,6 +281,36 @@ public int getAddVictoryTokens() { return 0; } + @Override + public int getAddCardsNextTurn() { + return 0; + } + + @Override + public int getAddActionsNextTurn() { + return 0; + } + + @Override + public int getAddGoldNextTurn() { + return 0; + } + + @Override + public int getAddBuysNextTurn() { + return 0; + } + + @Override + public boolean takeAnotherTurn() { + return false; + } + + @Override + public int takeAnotherTurnCardCount() { + return 0; + } + @Override public boolean trashForced() { return false; @@ -340,6 +371,13 @@ public boolean isAction() { return this instanceof ActionCard; } + @Override + public boolean isDuration(Player player) { + if (player == null || player.getInheritance() == null) + return this instanceof DurationCard; + return player.getInheritance() instanceof DurationCard; + } + @Override public boolean isAction(Player player) { return player.getInheritance() != null && this.getType() == player.getInheritance().getType(); From f07d9a63bf8805ad9c78cb9f4b6325aa5d922027 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 22:45:18 -0700 Subject: [PATCH 057/141] Inheritance: removing uncessary references to DurationCard interface. --- vdom/src/com/vdom/core/ActionCardImpl.java | 9 ++++----- vdom/src/com/vdom/core/BasePlayer.java | 3 +-- .../com/vdom/core/CallableActionCardImpl.java | 3 +-- vdom/src/com/vdom/core/EventCardImpl.java | 3 +-- vdom/src/com/vdom/core/Game.java | 19 +++++++++---------- vdom/src/com/vdom/core/MoveContext.java | 2 -- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 57cc6f272..74ae0aba9 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -11,7 +11,6 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CurseCard; -import com.vdom.api.DurationCard; import com.vdom.api.GameEvent; import com.vdom.api.GameEventListener; import com.vdom.api.TreasureCard; @@ -223,8 +222,8 @@ public void play(Game game, MoveContext context, boolean fromHand) { currentPlayer.hand.remove(this); if (trashOnUse) { currentPlayer.trash(this, null, context); - } else if (this instanceof DurationCard) { - currentPlayer.nextTurnCards.add((DurationCard) this); + } else if (this.isDuration(currentPlayer)) { + currentPlayer.nextTurnCards.add(this); } else { currentPlayer.playedCards.add(this); } @@ -1841,7 +1840,7 @@ private Card throneRoomKingsCourt(Game game, MoveContext context, Player current cardToPlay.cloneCount = 1; } - if (cardToPlay instanceof DurationCard && !cardToPlay.equals(Cards.tactician)) { + if (cardToPlay.isDuration(currentPlayer) && !cardToPlay.equals(Cards.tactician)) { // Need to move throning card to NextTurnCards first // (but does not play) if (!this.controlCard.movedToNextTurnPile) { @@ -5610,7 +5609,7 @@ private void bandOfMisfits(Game game, MoveContext context, Player currentPlayer) int idx = currentPlayer.playedCards.lastIndexOf(this); if (idx >= 0) currentPlayer.playedCards.remove(idx); currentPlayer.trash(this, null, context); - } else if (cardToPlay instanceof DurationCard && !cardToPlay.equals(Cards.outpost)) { + } else if (cardToPlay.isDuration(currentPlayer) && !cardToPlay.equals(Cards.outpost)) { if (!this.controlCard.movedToNextTurnPile) { this.controlCard.movedToNextTurnPile = true; int idx = currentPlayer.playedCards.lastIndexOf(this); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 49f28bb64..c9a6e6cc0 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -13,7 +13,6 @@ import com.vdom.api.CardCostComparator; import com.vdom.api.CardValueComparator; import com.vdom.api.CurseCard; -import com.vdom.api.DurationCard; import com.vdom.api.GameEvent; import com.vdom.api.GameEventListener; import com.vdom.api.TreasureCard; @@ -1156,7 +1155,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis if ( !card.isRuins() && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() - && !(card instanceof DurationCard) + && !(card.isDuration(context.player)) && !(card.isReserve()) && !(card.isTraveller()) && !card.equals(Cards.feast) diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 784607071..0d9115497 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -2,7 +2,6 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; -import com.vdom.api.DurationCard; import com.vdom.api.GameEvent; public class CallableActionCardImpl extends ActionCardImpl implements CallableCard { @@ -222,7 +221,7 @@ private void royalCarriage(Card resolvedAction, MoveContext context, Game game, cardToPlay.cloneCount = 1; } - if (cardToPlay instanceof DurationCard && !cardToPlay.equals(Cards.tactician)) { + if (cardToPlay.isDuration(currentPlayer) && !cardToPlay.equals(Cards.tactician)) { // Need to move royal carriage card to NextTurnCards first // (but does not play) if (!this.controlCard.movedToNextTurnPile) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 4268471d6..d26227c4d 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -6,7 +6,6 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; -import com.vdom.api.DurationCard; import com.vdom.api.EventCard; import com.vdom.api.GameEvent; import com.vdom.api.TreasureCard; @@ -181,7 +180,7 @@ private void bonfire(MoveContext context) { for (int i = 0; i < context.player.nextTurnCards.size(); i++) { Card nextTurnCard = context.player.nextTurnCards.get(i); if (nextTurnCard.equals(card)) { - if (nextTurnCard.behaveAsCard() instanceof DurationCard) { + if (nextTurnCard.isDuration(context.player)) { ((CardImpl)nextTurnCard).trashAfterPlay = true; context.player.trash(nextTurnCard, this.controlCard, context); } else { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 4f458fe02..24c8c43a3 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -18,7 +18,6 @@ import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CardCostComparator; -import com.vdom.api.DurationCard; import com.vdom.api.EventCard; import com.vdom.api.FrameworkEvent; import com.vdom.api.FrameworkEventHelper; @@ -593,8 +592,8 @@ protected List playerEndTurn(Player player, MoveContext context) // Can only have at most two consecutive turns for (Card card : player.nextTurnCards) { Card behaveAsCard = card.behaveAsCard(); - if ((behaveAsCard instanceof DurationCard) && ((DurationCard) behaveAsCard).takeAnotherTurn()) { - handCount = ((DurationCard) behaveAsCard).takeAnotherTurnCardCount(); + if (behaveAsCard.takeAnotherTurn()) { + handCount = behaveAsCard.takeAnotherTurnCardCount(); if (consecutiveTurnCounter <= 1) { result.add(new ExtraTurnInfo()); break; @@ -784,7 +783,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { /* Duration cards, horse traders, cards on prince*/ /* selectOption() must know if horse traders are set aside by reaction or by haven/gear or by prince. - * We put 2 cards in list durationCards to differentiate: + * We put 2 cards in list durationEffects to differentiate: * Examples (Curse is here a dummy card): * HorseTrader - (Curse) * Haven - Card set aside by haven or gear @@ -797,7 +796,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { ArrayList durationEffectsAreCards = new ArrayList(); for (Card card : player.nextTurnCards) { Card thisCard = card.behaveAsCard(); - if (thisCard instanceof DurationCard) { + if (thisCard.isDuration(player)) { /* Wiki: * Effects that resolve at the start of your turn can be resolved in any order; * this includes multiple plays of the same Duration card by a Throne Room variant. @@ -863,7 +862,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { while (!player.haven.isEmpty()) { /*gear could set 2 cards aside*/ // BUG: both cards set aside by Gear need to be added to hand at the same time - durationEffects.add((DurationCard) Cards.gear); + durationEffects.add(Cards.gear); durationEffects.add(player.haven.remove(0)); durationEffectsAreCards.add(false); durationEffectsAreCards.add(false); @@ -918,7 +917,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { durationEffectsAreCards.remove(selection); if(card.equals(Cards.prince)) { - if (!(card2 instanceof DurationCard)) { + if (!(card2.isDuration(player))) { player.playedByPrince.add(card2); } player.prince.remove(card2); @@ -944,12 +943,12 @@ protected void playerBeginTurn(Player player, MoveContext context) { Card horseTrader = player.horseTraders.remove(0); player.hand.add(horseTrader); drawToHand(context, horseTrader, 1); - } else if(card.behaveAsCard() instanceof DurationCard) { + } else if(card.behaveAsCard().isDuration(player)) { if(card.behaveAsCard().equals(Cards.haven) || card.behaveAsCard().equals(Cards.gear)) { player.hand.add(card2); } - DurationCard thisCard = (DurationCard) card.behaveAsCard(); + Card thisCard = card.behaveAsCard(); GameEvent event = new GameEvent(GameEvent.Type.PlayingDurationAction, context); event.card = card; @@ -1024,7 +1023,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { } if(card.behaveAsCard().equals(Cards.hireling) || card.behaveAsCard().equals(Cards.champion)) { - staysInPlayCards.add((DurationCard) card); + staysInPlayCards.add(card); } else { CardImpl behaveAsCard = (CardImpl) card.behaveAsCard(); behaveAsCard.cloneCount = 1; diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index 66ec7fb67..89966d49a 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -5,10 +5,8 @@ import java.util.HashMap; import java.util.HashSet; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CardCostComparator; -import com.vdom.api.DurationCard; import com.vdom.api.GameEventListener; import com.vdom.api.GameType; import com.vdom.api.TreasureCard; From d6fc2ab11043112641e4c641f370dd532d96bfbc Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 23:05:43 -0700 Subject: [PATCH 058/141] Inheritance: made isAttack() player relative. --- vdom/src/com/vdom/api/Card.java | 9 ++------- vdom/src/com/vdom/api/TreasureCard.java | 1 - vdom/src/com/vdom/comms/SelectCardOptions.java | 11 +++++++---- vdom/src/com/vdom/core/ActionCardImpl.java | 4 ++-- vdom/src/com/vdom/core/BasePlayer.java | 4 ++-- vdom/src/com/vdom/core/CardImpl.java | 7 +++++-- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/IndirectPlayer.java | 4 ++-- vdom/src/com/vdom/core/MoveContext.java | 4 ++-- vdom/src/com/vdom/core/RemotePlayer.java | 2 +- vdom/src/com/vdom/core/TreasureCardImpl.java | 2 +- vdom/src/com/vdom/players/VDomPlayerPatrick.java | 4 ++-- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 2ec80ef9d..a0a8f7109 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -31,17 +31,12 @@ public interface Card extends Serializable { public boolean costPotion(); public boolean isAction(); - - /** - * Is the card an action if it belonged to the current player? - * @param player - * @return - */ + public boolean isAction(Player player); public boolean isDuration(Player player); - public boolean isAttack(); + public boolean isAttack(Player player); public boolean isPrize(); diff --git a/vdom/src/com/vdom/api/TreasureCard.java b/vdom/src/com/vdom/api/TreasureCard.java index ac2ee59a5..e12e1644b 100644 --- a/vdom/src/com/vdom/api/TreasureCard.java +++ b/vdom/src/com/vdom/api/TreasureCard.java @@ -11,5 +11,4 @@ public interface TreasureCard extends Card { public boolean playTreasure(MoveContext context); - public boolean isAttack(); } diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index 2c0ccfe84..24fac7fc7 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -10,6 +10,7 @@ import com.vdom.api.VictoryCard; import com.vdom.core.Cards; import com.vdom.core.MoveContext; +import com.vdom.core.Player; /** * Gives information about cards that are selected by the player from the table (piles, hand, play) @@ -178,12 +179,14 @@ public boolean checkValid(MyCard c, int cost) { return true; } - public boolean checkValid(Card c, boolean cardIsVictory) { - return checkValid(c, 0, cardIsVictory); + public boolean checkValid(Card c, boolean cardIsVictory, MoveContext context) { + return checkValid(c, 0, cardIsVictory, context); } /* Note: This method must be synchrony with checkValid(MyCard c, int cost) */ - public boolean checkValid(Card c, int cost, boolean cardIsVictory) { + public boolean checkValid(Card c, int cost, boolean cardIsVictory, MoveContext context) { + + Player p = context != null ? context.player : null; if ((maxCost >= 0) && (cost > (c.costPotion() ? maxCost : maxCostWithoutPotion))) return false; if ((minCost >= 0) && (cost < minCost)) return false; @@ -200,7 +203,7 @@ public boolean checkValid(Card c, int cost, boolean cardIsVictory) { if (isNonRats && c.equals(Cards.rats)) return false; if (c.equals(Cards.grandMarket) && copperCountInPlay > 0) return false; if (isNonShelter && c.isShelter()) return false; - if (isAttack && !c.isAttack()) return false; + if (isAttack && !c.isAttack(p)) return false; if (isAction && !c.isAction()) return false; if (isBuyPhase && !Cards.isSupplyCard(c) && !c.isEvent()) return false; diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 74ae0aba9..fc134ed4a 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -212,7 +212,7 @@ public void play(Game game, MoveContext context, boolean fromHand) { context.actions += game.countChampionsInPlay(currentPlayer); - if (isAttack()) + if (isAttack(currentPlayer)) attackPlayed(context, game, currentPlayer); if (this.numberTimesAlreadyPlayed == 0 && this == actualCard) { @@ -5086,7 +5086,7 @@ public void isTrashed(MoveContext context) { for (Card c : context.game.getCardsInGame()) { - if (Cards.isSupplyCard(c) && c.isAttack() && context.game.getPile(c).getCount() > 0) { + if (Cards.isSupplyCard(c) && c.isAttack(null) && context.game.getPile(c).getCount() > 0) { attackCardAvailable = true; break; } diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index c9a6e6cc0..998fbffea 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -432,7 +432,7 @@ public Card[] pickOutCards(CardList cards, int num, Card[] cardsToMatch) { protected ArrayList getAttackCardsLeft() { ArrayList options = new ArrayList(); for (AbstractCardPile pile : game.piles.values()) { - if (pile.getCount() > 0 && pile.card().isAttack()) { + if (pile.getCount() > 0 && pile.card().isAttack(null)) { options.add(pile.card()); } } @@ -2694,7 +2694,7 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { if (!this.hand.contains(Cards.moat)) { for (Card card : cl) { - if (card.isAttack()) { + if (card.isAttack(context.player)) { return card; } } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 58e0b5770..93163fabe 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -380,12 +380,15 @@ public boolean isDuration(Player player) { @Override public boolean isAction(Player player) { + //TODO: redo? return player.getInheritance() != null && this.getType() == player.getInheritance().getType(); } @Override - public boolean isAttack() { - return isAttack; + public boolean isAttack(Player player) { + if (player == null || player.getInheritance() == null) + return isAttack; + return ((CardImpl)player.getInheritance()).isAttack; } @Override public boolean isPrize() { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index d26227c4d..bfcdb125a 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -276,7 +276,7 @@ private void quest(MoveContext context) { if (option == QuestOption.DiscardAttack) { Set attackSet = new HashSet(); for (Card card : hand) { - if (card.behaveAsCard().isAttack()) { + if (card.behaveAsCard().isAttack(player)) { attackSet.add(card); } } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 06f5e2796..403fb6732 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -101,7 +101,7 @@ private Card[] getFromHandOrPlayed(boolean fromTheHand, MoveContext context, Sel ArrayList handList = new ArrayList(); for (Card card : localHand) { - if (sco.checkValid(card, card.getCost(context), card.isVictory(context))) { + if (sco.checkValid(card, card.getCost(context), card.isVictory(context), context)) { handList.add(card); sco.addValidCard(cardToInt(card)); } @@ -155,7 +155,7 @@ private Card getFromTable(MoveContext context, SelectCardOptions sco) { boolean hasTokens = context.game.getPlayerSupplyTokens(card, context.getPlayer()).size() > 0; if ( !(card.isEvent() && sco.cardResponsible != null && sco.cardResponsible.equals(Cards.contraband) ) && (sco.allowEmpty || !context.game.isPileEmpty(card))) { - if ( sco.checkValid(card, card.getCost(context), card.isVictory(context)) + if ( sco.checkValid(card, card.getCost(context), card.isVictory(context), null) && (!(sco.noTokens && hasTokens)) && ( (!context.cantBuy.contains(card) && (context.canBuyCards || card.isEvent())) || !sco.pickType.equals(PickType.BUY)) diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index 89966d49a..be9a494e7 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -162,7 +162,7 @@ public int countTravellerCardsInPlayThisTurn() { public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { int actionsInPlay = 0; for (Card c : getPlayedCards()) { - if ((type == CardsInPlay.ATTACK && c.isAttack()) + if ((type == CardsInPlay.ATTACK && c.isAttack(player)) || (type == CardsInPlay.TRAVELLER && c.isTraveller()) || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; @@ -171,7 +171,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { for (Card c : player.nextTurnCards) { if (c instanceof CardImpl && ((CardImpl)c).trashAfterPlay) continue; - if ((type == CardsInPlay.ATTACK && c.isAttack()) + if ((type == CardsInPlay.ATTACK && c.isAttack(player)) || (type == CardsInPlay.TRAVELLER && c.isTraveller()) || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 118aa3e55..e8a9471cf 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -125,7 +125,7 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla card.isEvent = c.isEvent(); card.isReserve = c.isReserve(); card.isTraveller = c.isTraveller(); - card.isAttack = c.isAttack() || c.equals(Cards.virtualKnight); + card.isAttack = c.isAttack(null) || c.equals(Cards.virtualKnight); if (c.equals(Cards.virtualRuins)) card.isRuins = true; else diff --git a/vdom/src/com/vdom/core/TreasureCardImpl.java b/vdom/src/com/vdom/core/TreasureCardImpl.java index 96dd7822e..476ddf0dc 100644 --- a/vdom/src/com/vdom/core/TreasureCardImpl.java +++ b/vdom/src/com/vdom/core/TreasureCardImpl.java @@ -94,7 +94,7 @@ public boolean playTreasure(MoveContext context, boolean isClone) { game.broadcastEvent(event); - if (isAttack()) + if (isAttack(player)) attackPlayed(context, game, player); if (!isClone) diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index ec1ca9721..018c7dde4 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -2024,7 +2024,7 @@ public void gameEvent(GameEvent event) { if (card.isAction()) { ActionCard ac = (ActionCard) card; this.opponents.get(event.player.playerNumber).putActionCard(card); - if (ac.isAttack()) { + if (ac.isAttack(event.player)) { this.opponents.get(event.player.playerNumber).setAttacking(true); } } @@ -2310,7 +2310,7 @@ private boolean shouldReEvaluateStrategy() { return true; } - if (this.opponents != null && this.opponents.getIsAttacking() && this.strategyCard != null && !this.strategyCard.isAttack()) { + if (this.opponents != null && this.opponents.getIsAttacking() && this.strategyCard != null && !this.strategyCard.isAttack(this)) { return true; } From 8e69c8adcc215402b1b7ab9c8ea2f75fee01629e Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 23:23:20 -0700 Subject: [PATCH 059/141] Inheritance: Making isKnight() player specific --- vdom/src/com/vdom/api/Card.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 13 ++++--------- vdom/src/com/vdom/core/CallableActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 6 ++++-- vdom/src/com/vdom/core/Game.java | 10 +++++----- vdom/src/com/vdom/core/RemotePlayer.java | 2 +- vdom/src/com/vdom/core/VariableCardPile.java | 2 +- 7 files changed, 17 insertions(+), 20 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index a0a8f7109..ad6057224 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -46,7 +46,7 @@ public interface Card extends Serializable { public boolean isRuins(); - public boolean isKnight(); + public boolean isKnight(Player player); public boolean isOverpay(); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index fc134ed4a..7fe5a780d 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1554,7 +1554,7 @@ private void ambassador(Game game, MoveContext context, Player currentPlayer) { Card virtCard = card; AbstractCardPile pile; - if (card.isKnight()) { + if (card.isKnight(null)) { virtCard = Cards.virtualKnight; } else if (card.isRuins()) { virtCard = Cards.virtualRuins; @@ -1836,7 +1836,7 @@ private Card throneRoomKingsCourt(Game game, MoveContext context, Player current cardToPlay.numberTimesAlreadyPlayed = 0; context.freeActionInEffect--; // If the cardToPlay was a knight, and was trashed, reset clonecount - if (cardToPlay.isKnight() && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { + if (cardToPlay.isKnight(currentPlayer) && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { cardToPlay.cloneCount = 1; } @@ -2193,7 +2193,7 @@ private void jester(Game game, MoveContext context, Player currentPlayer) { else if (Cards.isSupplyCard(draw)) { AbstractCardPile pile; - if (draw.isKnight()) { + if (draw.isKnight(null)) { virtCard = Cards.virtualKnight; } else if (draw.isRuins()) { virtCard = Cards.virtualRuins; @@ -5193,11 +5193,6 @@ public boolean isRuins() { } } - @Override - public boolean isKnight() { - return isKnight; - } - @Override public boolean isLooter() { switch (this.controlCard.getType()) { @@ -5510,7 +5505,7 @@ private void knight(MoveContext context, Player currentPlayer) { targetPlayer.trash(cardToTrash, this.controlCard, targetContext); // If the card trashed was a knight, the attacking knight should be trashed as well - if (cardToTrash.isKnight() && currentPlayer.playedCards.contains(this.controlCard) && currentPlayer.playedCards.getLastCard() == this.controlCard) { + if (cardToTrash.isKnight(targetPlayer) && currentPlayer.playedCards.contains(this.controlCard) && currentPlayer.playedCards.getLastCard() == this.controlCard) { currentPlayer.trash(currentPlayer.playedCards.removeLastCard(), cardToTrash, context); } } diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 0d9115497..3ecfe1322 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -217,7 +217,7 @@ private void royalCarriage(Card resolvedAction, MoveContext context, Game game, cardToPlay.numberTimesAlreadyPlayed = 0; //TODO: not sure if this is always right context.freeActionInEffect--; // If the cardToPlay was a knight, and was trashed, reset clonecount - if (cardToPlay.isKnight() && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { + if (cardToPlay.isKnight(currentPlayer) && !currentPlayer.playedCards.contains(cardToPlay) && game.trashPile.contains(cardToPlay)) { cardToPlay.cloneCount = 1; } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 93163fabe..87b3b3306 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -403,8 +403,10 @@ public boolean isRuins() { return isRuins; } @Override - public boolean isKnight() { - return isKnight; + public boolean isKnight(Player player) { + if (player == null || player.getInheritance() == null) + return isKnight; + return ((CardImpl)player.getInheritance()).isKnight; } @Override diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 24c8c43a3..6e204f97b 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1604,7 +1604,7 @@ Card playBuy(MoveContext context, Card buy) { if (buy.costPotion()) { context.potions--; - } else if (!(buy instanceof VictoryCard) && !buy.isKnight() && cost < 5 && !buy.isEvent()) { + } else if (!(buy instanceof VictoryCard) && !buy.isKnight(null) && cost < 5 && !buy.isEvent()) { for (int i = 1; i <= context.countCardsInPlay(Cards.talisman); i++) { if (!buy.isRuins() || (card != null && card.equals(getTopRuinsCard()))) { context.getPlayer().gainNewCard(buy, Cards.talisman, context); @@ -2032,7 +2032,7 @@ protected void initPlayerCards() { tradeRouteValue = 0; if (isCardInGame(Cards.tradeRoute)) { for (AbstractCardPile pile : piles.values()) { - if ((pile.card() instanceof VictoryCard) && !pile.card().isKnight() && !pile.isBlackMarket()) { + if ((pile.card() instanceof VictoryCard) && !pile.card().isKnight(null) && !pile.isBlackMarket()) { pile.setTradeRouteToken(); } } @@ -2284,7 +2284,7 @@ protected void initCards() { pile.card().getExpansion() != null && pile.card().isShelter() == false && pile.card().isRuins() == false && - (pile.card().isKnight() == false || !alreadyCountedKnights) && + (pile.card().isKnight(null) == false || !alreadyCountedKnights) && pile.card().getExpansion().equals("DarkAges")) { chanceForShelters += 0.1; @@ -2296,7 +2296,7 @@ protected void initCards() { break; } - if (pile.card().isKnight()) + if (pile.card().isKnight(null)) { alreadyCountedKnights = true; } @@ -2948,7 +2948,7 @@ protected Card takeFromPile(Card card) { protected Card takeFromPile(Card card, MoveContext context) { if (context == null || !context.blackMarketBuyPhase) { - if (card.isKnight()) card = Cards.virtualKnight; + if (card.isKnight(null)) card = Cards.virtualKnight; if (card.isRuins()) card = Cards.virtualRuins; } diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index e8a9471cf..56e730231 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -331,7 +331,7 @@ else if (cardsInPlay.get(i).isRuins()) { i_virtualKnight = i; } - else if (cardsInPlay.get(i).isKnight()) + else if (cardsInPlay.get(i).isKnight(null)) { knightSize += player.getMyCardCount(cardsInPlay.get(i)); } diff --git a/vdom/src/com/vdom/core/VariableCardPile.java b/vdom/src/com/vdom/core/VariableCardPile.java index 3ffed9871..482a82bf7 100644 --- a/vdom/src/com/vdom/core/VariableCardPile.java +++ b/vdom/src/com/vdom/core/VariableCardPile.java @@ -62,7 +62,7 @@ public void addCard(Card card) { switch (type) { case KnightsPile: - if (card.isKnight()) { + if (card.isKnight(null)) { cards.add(0, card); } break; From 5a1b160a6c721144b144fb72537ec8c3ce04d467 Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 23:47:08 -0700 Subject: [PATCH 060/141] Inheritance: making isRuins() player specific --- vdom/src/com/vdom/api/Card.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 42 ++----------------- vdom/src/com/vdom/core/BasePlayer.java | 42 +++++++++---------- vdom/src/com/vdom/core/CardImpl.java | 6 ++- vdom/src/com/vdom/core/Game.java | 6 +-- vdom/src/com/vdom/core/RemotePlayer.java | 4 +- vdom/src/com/vdom/core/VariableCardPile.java | 2 +- vdom/src/com/vdom/players/VDomPlayerEarl.java | 2 +- 8 files changed, 36 insertions(+), 70 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index ad6057224..cc62f0d46 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -44,7 +44,7 @@ public interface Card extends Serializable { public boolean isLooter(); - public boolean isRuins(); + public boolean isRuins(Player player); public boolean isKnight(Player player); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 7fe5a780d..4572acf9b 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1556,7 +1556,7 @@ private void ambassador(Game game, MoveContext context, Player currentPlayer) { AbstractCardPile pile; if (card.isKnight(null)) { virtCard = Cards.virtualKnight; - } else if (card.isRuins()) { + } else if (card.isRuins(null)) { virtCard = Cards.virtualRuins; } pile = game.getPile(virtCard); @@ -2195,7 +2195,7 @@ else if (Cards.isSupplyCard(draw)) AbstractCardPile pile; if (draw.isKnight(null)) { virtCard = Cards.virtualKnight; - } else if (draw.isRuins()) { + } else if (draw.isRuins(null)) { virtCard = Cards.virtualRuins; } pile = game.getPile(virtCard); @@ -5179,42 +5179,6 @@ public void isGained(MoveContext context) { } }*/ - @Override - public boolean isRuins() { - switch (this.controlCard.getType()) { - case AbandonedMine: - case RuinedLibrary: - case RuinedMarket: - case RuinedVillage: - case Survivors: - return true; - default: - return false; - } - } - - @Override - public boolean isLooter() { - switch (this.controlCard.getType()) { - case Cultist: - case DeathCart: - case Marauder: - return true; - default: - return false; - } - } - - @Override - public boolean isReserve() { - return isReserve; - } - - @Override - public boolean isTraveller() { - return isTraveller; - } - private void survivors(MoveContext context, Game game, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 2; i++) { @@ -5446,7 +5410,7 @@ private void vagrant(MoveContext context, Game game, Player currentPlayer) Card c = game.draw(context, controlCard, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); - if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins())) { + if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins(currentPlayer))) { currentPlayer.hand.add(c); } else { currentPlayer.putOnTopOfDeck(c, context, true); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 998fbffea..d52560e89 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -540,7 +540,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { // Just add in the non-victory cards... for (Card card : context.attackedPlayer.getHand()) { - if (!shouldDiscard(card)) { + if (!shouldDiscard(card, context.attackedPlayer)) { keepers.add(card); } else { discards.add(card); @@ -682,7 +682,7 @@ public Card[] cellar_cardsToDiscard(MoveContext context) { else if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.copper)) { cards.add(card); } - else if (shouldDiscard(card)) { + else if (shouldDiscard(card, context.player)) { cards.add(card); } } @@ -695,11 +695,11 @@ public boolean library_shouldKeepAction(MoveContext context, ActionCard action) if (context.getActionsLeft() == 0) { return false; } - if (action.isRuins()) { + if (action.isRuins(context.player)) { return false; } for (Card card : context.getPlayer().getHand()) { - if (card.isAction() && !card.isRuins()) { + if (card.isAction() && !card.isRuins(context.player)) { return false; } } @@ -714,7 +714,7 @@ public boolean spy_shouldDiscard(MoveContext context, Player targetPlayer, Card || card.equals(Cards.copper) || card.equals(Cards.curse) || card.isShelter() - || card.isRuins()) + || card.isRuins(targetPlayer)) ret = false; else { ret = true; @@ -740,7 +740,7 @@ public Card[] secretChamber_cardsToDiscard(MoveContext context) { // Discard all victory cards ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (shouldDiscard(card)) { + if (shouldDiscard(card, context.player)) { cards.add(card); } } @@ -781,7 +781,7 @@ public TorturerOption torturer_attack_chooseOption(MoveContext context) { if (h.size() < 5) { int count = 0; for (Card c : h) { - if (shouldDiscard(c) || c.equals(Cards.copper)) { + if (shouldDiscard(c, context.attackedPlayer) || c.equals(Cards.copper)) { count++; } } @@ -795,7 +795,7 @@ public TorturerOption torturer_attack_chooseOption(MoveContext context) { else { int count = 0; for (Card c : h) { - if (shouldDiscard(c)) { + if (shouldDiscard(c, context.attackedPlayer)) { count++; } } @@ -1039,7 +1039,7 @@ public Card[] warehouse_cardsToDiscard(MoveContext context) { ArrayList cardsToDiscard = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (shouldDiscard(card)) { + if (shouldDiscard(card, context.getPlayer())) { cardsToDiscard.add(card); } @@ -1152,7 +1152,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis int maxCost = -1; for (Card card : cardList) { if (card.isAction() && card.getCost(context) <= 4 && !card.costPotion()) { - if ( !card.isRuins() + if ( !card.isRuins(context.player) && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() && !(card.isDuration(context.player)) @@ -1249,7 +1249,7 @@ public boolean navigator_shouldDiscardTopCards(MoveContext context, Card[] cards // Discard them if there is more than 2 victory cards int victoryCount = 0; for (Card card : cards) { - if (shouldDiscard(card)) { + if (shouldDiscard(card, context.player)) { victoryCount++; } } @@ -1915,8 +1915,8 @@ public boolean isCurse(Card card) { return card instanceof CurseCard; } - public boolean shouldDiscard(Card card) { - return isCurse(card) || isOnlyVictory(card) || card.isShelter() || card.isRuins(); + public boolean shouldDiscard(Card card, Player player) { + return isCurse(card) || isOnlyVictory(card) || card.isShelter() || card.isRuins(player); } public boolean shouldBuyPotion() { @@ -2162,7 +2162,7 @@ public Card[] inn_cardsToDiscard(MoveContext context) { ArrayList cardsToDiscard = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (shouldDiscard(card)) { + if (shouldDiscard(card, context.player)) { cardsToDiscard.add(card); } @@ -2327,7 +2327,7 @@ public Card squire_cardToObtain(MoveContext context) { public boolean catacombs_shouldDiscardTopCards(MoveContext context, Card[] array) { int discards = 0; for (Card c : array) - if (shouldDiscard(c)) + if (shouldDiscard(c, context.player)) discards++; return (discards > 1); @@ -2372,7 +2372,7 @@ public Card deathCart_actionToTrash(MoveContext context) { for (Card c : context.player.hand) { - if (c.isRuins()) { + if (c.isRuins(context.player)) { return c; } } @@ -2449,7 +2449,7 @@ public boolean ironmonger_shouldDiscard(MoveContext context, Card card) { if (card.equals(Cards.copper) || card.equals(Cards.masterpiece)) { return true; } - return this.shouldDiscard(card); + return this.shouldDiscard(card, context.player); } @Override @@ -2767,7 +2767,7 @@ public Card[] urchin_attack_cardsToKeep(MoveContext context) // Just add in the non-victory cards... for (Card card : context.attackedPlayer.getHand()) { - if (!shouldDiscard(card)) { + if (!shouldDiscard(card, context.attackedPlayer)) { keepers.add(card); } else { discards.add(card); @@ -3167,7 +3167,7 @@ public DoctorOverpayOption doctor_chooseOption(MoveContext context, Card card) { DoctorOverpayOption doo = DoctorOverpayOption.PutItBack; - if (shouldDiscard(card)) { + if (shouldDiscard(card, context.player)) { doo = DoctorOverpayOption.DiscardIt; } @@ -3197,7 +3197,7 @@ public Card herald_cardTopDeck(MoveContext context, Card[] cardList) for (Card c : cardList) { - if (!shouldDiscard(c) && !c.equals(Cards.copper)) + if (!shouldDiscard(c, context.player) && !c.equals(Cards.copper)) { cardToReturn = c; break; @@ -3574,7 +3574,7 @@ public Card transmogrify_cardToTrash(MoveContext context) { if (!context.game.isCardInGame(Cards.poorHouse)) { for (Card c : hand) { - if (c.isRuins()) + if (c.isRuins(context.getPlayer())) return c; } if (hand.contains(Cards.copper)) return Cards.copper; diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 87b3b3306..69b4dba9f 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -399,8 +399,10 @@ public boolean isShelter() { return isShelter; } @Override - public boolean isRuins() { - return isRuins; + public boolean isRuins(Player player) { + if (player == null || player.getInheritance() == null) + return isRuins; + return ((CardImpl)player.getInheritance()).isRuins; } @Override public boolean isKnight(Player player) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 6e204f97b..ece0e2005 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1606,7 +1606,7 @@ Card playBuy(MoveContext context, Card buy) { context.potions--; } else if (!(buy instanceof VictoryCard) && !buy.isKnight(null) && cost < 5 && !buy.isEvent()) { for (int i = 1; i <= context.countCardsInPlay(Cards.talisman); i++) { - if (!buy.isRuins() || (card != null && card.equals(getTopRuinsCard()))) { + if (!buy.isRuins(null) || (card != null && card.equals(getTopRuinsCard()))) { context.getPlayer().gainNewCard(buy, Cards.talisman, context); } } @@ -2283,7 +2283,7 @@ protected void initCards() { pile.card() != null && pile.card().getExpansion() != null && pile.card().isShelter() == false && - pile.card().isRuins() == false && + pile.card().isRuins(null) == false && (pile.card().isKnight(null) == false || !alreadyCountedKnights) && pile.card().getExpansion().equals("DarkAges")) { @@ -2949,7 +2949,7 @@ protected Card takeFromPile(Card card) { protected Card takeFromPile(Card card, MoveContext context) { if (context == null || !context.blackMarketBuyPhase) { if (card.isKnight(null)) card = Cards.virtualKnight; - if (card.isRuins()) card = Cards.virtualRuins; + if (card.isRuins(null)) card = Cards.virtualRuins; } AbstractCardPile pile = getPile(card); diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 56e730231..9bddfede3 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -129,7 +129,7 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla if (c.equals(Cards.virtualRuins)) card.isRuins = true; else - card.isRuins = c.isRuins(); + card.isRuins = c.isRuins(null); card.pile = MyCard.SUPPLYPILE; @@ -323,7 +323,7 @@ public Event fullStatusPacket(MoveContext context, Player player, boolean isFina { i_virtualRuins = i; } - else if (cardsInPlay.get(i).isRuins()) + else if (cardsInPlay.get(i).isRuins(null)) { ruinsSize += player.getMyCardCount(cardsInPlay.get(i)); } diff --git a/vdom/src/com/vdom/core/VariableCardPile.java b/vdom/src/com/vdom/core/VariableCardPile.java index 482a82bf7..e0ef825b7 100644 --- a/vdom/src/com/vdom/core/VariableCardPile.java +++ b/vdom/src/com/vdom/core/VariableCardPile.java @@ -67,7 +67,7 @@ public void addCard(Card card) { } break; case RuinsPile: - if (card.isRuins()) { + if (card.isRuins(null)) { cards.add(0, card); } break; diff --git a/vdom/src/com/vdom/players/VDomPlayerEarl.java b/vdom/src/com/vdom/players/VDomPlayerEarl.java index 05626b543..df9a2a0d3 100644 --- a/vdom/src/com/vdom/players/VDomPlayerEarl.java +++ b/vdom/src/com/vdom/players/VDomPlayerEarl.java @@ -821,7 +821,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { if ( !(card instanceof VictoryCard) && !(card instanceof CurseCard) && !(card.isShelter()) - && !(card.isRuins())) { + && !(card.isRuins(this))) { cards.add(card); } } From bc86bfc30fa91813129d945fae0d47659097699b Mon Sep 17 00:00:00 2001 From: dominionator Date: Sun, 24 Jan 2016 23:57:43 -0700 Subject: [PATCH 061/141] Inheritance: making isReserve() and isTraveller() player specific --- vdom/src/com/vdom/api/Card.java | 4 ++-- vdom/src/com/vdom/core/BasePlayer.java | 8 ++++---- vdom/src/com/vdom/core/CardImpl.java | 12 ++++++++---- vdom/src/com/vdom/core/MoveContext.java | 4 ++-- vdom/src/com/vdom/core/Player.java | 2 +- vdom/src/com/vdom/core/RemotePlayer.java | 4 ++-- vdom/src/com/vdom/core/Util.java | 8 ++++---- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index cc62f0d46..3f64590d0 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -52,9 +52,9 @@ public interface Card extends Serializable { public boolean isEvent(); - public boolean isReserve(); + public boolean isReserve(Player player); - public boolean isTraveller(); + public boolean isTraveller(Player player); public int getAddCards(); diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index d52560e89..002d6ed35 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -1156,8 +1156,8 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() && !(card.isDuration(context.player)) - && !(card.isReserve()) - && !(card.isTraveller()) + && !(card.isReserve(context.player)) + && !(card.isTraveller(context.player)) && !card.equals(Cards.feast) && !card.equals(Cards.embargo) && !card.equals(Cards.pillage) @@ -3307,14 +3307,14 @@ public CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCa //use guide to cycle faster if have Travellers in deck boolean handHasTraveller = false; for (Card handCard : hand) { - if (handCard.isTraveller()) { + if (handCard.isTraveller(context.getPlayer())) { handHasTraveller = true; break; } } if (!handHasTraveller) { for (Card card : context.getPlayer().getDistinctCards()) { - if (card.isTraveller()) { + if (card.isTraveller(context.getPlayer())) { return c; } } diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 69b4dba9f..62ffa0c10 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -429,15 +429,19 @@ public boolean isEvent() } @Override - public boolean isReserve() + public boolean isReserve(Player player) { - return isReserve; + if (player == null || player.getInheritance() == null) + return isReserve; + return ((CardImpl)player.getInheritance()).isReserve; } @Override - public boolean isTraveller() + public boolean isTraveller(Player player) { - return isTraveller; + if (player == null || player.getInheritance() == null) + return isTraveller; + return ((CardImpl)player.getInheritance()).isTraveller; } @Override diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index be9a494e7..ed75ad0d6 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -163,7 +163,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { int actionsInPlay = 0; for (Card c : getPlayedCards()) { if ((type == CardsInPlay.ATTACK && c.isAttack(player)) - || (type == CardsInPlay.TRAVELLER && c.isTraveller()) + || (type == CardsInPlay.TRAVELLER && c.isTraveller(player)) || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; } @@ -172,7 +172,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { if (c instanceof CardImpl && ((CardImpl)c).trashAfterPlay) continue; if ((type == CardsInPlay.ATTACK && c.isAttack(player)) - || (type == CardsInPlay.TRAVELLER && c.isTraveller()) + || (type == CardsInPlay.TRAVELLER && c.isTraveller(player)) || (type == CardsInPlay.ACTION && c.isAction())) { actionsInPlay++; } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index cf5c0bbcc..63c8b88b0 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1066,7 +1066,7 @@ public void discard(Card card, Card responsible, MoveContext context, boolean co context.game.broadcastEvent(event); } } - else if(!commandedDiscard && cleanup && card.isTraveller()) { + else if(!commandedDiscard && cleanup && card.isTraveller(this)) { exchange = traveller_exchange(context, card); if (exchange != null) { // Return to the pile diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 9bddfede3..36fe9de33 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -123,8 +123,8 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla card.isLooter = c.isLooter(); card.isOverpay = c.isOverpay(); card.isEvent = c.isEvent(); - card.isReserve = c.isReserve(); - card.isTraveller = c.isTraveller(); + card.isReserve = c.isReserve(null); + card.isTraveller = c.isTraveller(null); card.isAttack = c.isAttack(null) || c.equals(Cards.virtualKnight); if (c.equals(Cards.virtualRuins)) card.isRuins = true; diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index b82a50b61..1ac5fd914 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -687,8 +687,8 @@ public int compare(Card card0, Card card1) { static public class CardTravellerComparator implements Comparator { @Override public int compare(Card card0, Card card1) { - if(card0.isTraveller()) { - if(card1.isTraveller()) { + if(card0.isTraveller(null)) { + if(card1.isTraveller(null)) { if(card0.getCost(null) > card1.getCost(null)) { return -1; } else if(card0.getCost(null) < card1.getCost(null)) { @@ -699,7 +699,7 @@ public int compare(Card card0, Card card1) { } else { return -1; } - } else if(card1.isTraveller()) { + } else if(card1.isTraveller(null)) { return 1; } else { return 0; @@ -726,7 +726,7 @@ private static int getTavernCompareVal(Card c) { if (c.equals(Cards.distantLands)) { return 3; } - if (c.isReserve()) { + if (c.isReserve(null)) { return 1; } if (c.equals(Cards.copper)) { From 63ec1721003b0c14f0fe40eaa49f9fa2c3d9282b Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 25 Jan 2016 22:21:01 -0700 Subject: [PATCH 062/141] Inheritance: Making isAction player specific. --- vdom/src/com/vdom/api/Card.java | 4 +- .../src/com/vdom/comms/SelectCardOptions.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 37 +++---- vdom/src/com/vdom/core/BasePlayer.java | 96 +++++++++---------- .../com/vdom/core/CallableActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 12 +-- vdom/src/com/vdom/core/Game.java | 4 +- vdom/src/com/vdom/core/IndirectPlayer.java | 2 +- vdom/src/com/vdom/core/MoveContext.java | 6 +- vdom/src/com/vdom/core/Player.java | 34 +++---- vdom/src/com/vdom/core/QuickPlayPlayer.java | 8 +- vdom/src/com/vdom/core/Util.java | 6 +- vdom/src/com/vdom/core/VariableCardPile.java | 2 +- .../src/com/vdom/players/VDomPlayerChuck.java | 4 +- vdom/src/com/vdom/players/VDomPlayerEarl.java | 30 +++--- .../com/vdom/players/VDomPlayerPatrick.java | 91 ++++++++---------- .../src/com/vdom/players/VDomPlayerSarah.java | 8 +- 17 files changed, 169 insertions(+), 179 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 3f64590d0..940dc03ea 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -29,9 +29,7 @@ public interface Card extends Serializable { public boolean isVictory(MoveContext context); public boolean costPotion(); - - public boolean isAction(); - + public boolean isAction(Player player); public boolean isDuration(Player player); diff --git a/vdom/src/com/vdom/comms/SelectCardOptions.java b/vdom/src/com/vdom/comms/SelectCardOptions.java index 24fac7fc7..6bb185d8c 100644 --- a/vdom/src/com/vdom/comms/SelectCardOptions.java +++ b/vdom/src/com/vdom/comms/SelectCardOptions.java @@ -204,7 +204,7 @@ public boolean checkValid(Card c, int cost, boolean cardIsVictory, MoveContext c if (c.equals(Cards.grandMarket) && copperCountInPlay > 0) return false; if (isNonShelter && c.isShelter()) return false; if (isAttack && !c.isAttack(p)) return false; - if (isAction && !c.isAction()) return false; + if (isAction && !c.isAction(p)) return false; if (isBuyPhase && !Cards.isSupplyCard(c) && !c.isEvent()) return false; if (isSupplyCard && !Cards.isSupplyCard(c)) return false; diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 4572acf9b..0d182d04d 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -15,6 +15,7 @@ import com.vdom.api.GameEventListener; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; +import com.vdom.core.Cards.Type; import com.vdom.core.MoveContext.PileSelection; import com.vdom.core.Player.AmuletOption; import com.vdom.core.Player.JesterOption; @@ -1150,7 +1151,7 @@ private void prince(Game game, MoveContext context, Player currentPlayer) { card = null; } - if (card != null && card.isAction() && card.getCost(context) <= 4 && !card.costPotion()) { + if (card != null && card.isAction(currentPlayer) && card.getCost(context) <= 4 && !card.costPotion()) { currentPlayer.prince.add(currentPlayer.playedCards.remove(currentPlayer.playedCards.lastIndexOf((Card) this.controlCard))); this.controlCard.stopImpersonatingCard(); @@ -1326,7 +1327,7 @@ private void mine(MoveContext context, Player currentPlayer) { private void university(MoveContext context, Player currentPlayer) { ActionCard cardToObtain = currentPlayer.controlPlayer.university_actionCardToObtain(context); - if (cardToObtain != null && cardToObtain.isAction() && cardToObtain.getCost(context) <= 5 && !cardToObtain.costPotion()) { + if (cardToObtain != null && cardToObtain.isAction(null) && cardToObtain.getCost(context) <= 5 && !cardToObtain.costPotion()) { currentPlayer.gainNewCard(cardToObtain, this.controlCard, context); } } @@ -1357,7 +1358,7 @@ private void transmute(MoveContext context, Player currentPlayer) { } else { currentPlayer.hand.remove(cardToTrash); currentPlayer.trash(cardToTrash, this.controlCard, context); - if (cardToTrash.isAction()) { + if (cardToTrash.isAction(cardToTrash.getType() == Type.Fortress ? currentPlayer : null )) { currentPlayer.gainNewCard(Cards.duchy, this.controlCard, context); } if (cardToTrash instanceof TreasureCard) { @@ -1796,7 +1797,7 @@ private Card throneRoomKingsCourt(Game game, MoveContext context, Player current ArrayList actionCards = new ArrayList(); ActionCardImpl cardToPlay = null; for (Card card : currentPlayer.hand) { - if (card.isAction()) { + if (card.isAction(currentPlayer)) { actionCards.add(card); } } @@ -1928,7 +1929,7 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { if (card != null) { player.reveal(card, this.controlCard, playerContext); - if (card instanceof TreasureCard || card.isAction()) { + if (card instanceof TreasureCard || card.isAction(player)) { cardToDiscard.add(card); } else { topOfTheDeck.add(card); @@ -2062,7 +2063,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(context, controlCard, -1)) != null && !(draw.isAction()) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(context, controlCard, -1)) != null && !(draw.isAction(currentPlayer)) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -3046,7 +3047,7 @@ private void shantyTown(Game game, MoveContext context, Player currentPlayer) { for (Card card : currentPlayer.hand) { currentPlayer.reveal(card, this.controlCard, context); - if (card.isAction()) { + if (card.isAction(currentPlayer)) { actions = true; } } @@ -3132,7 +3133,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla while ((draw = game.draw(context, controlCard, -1)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); - if(!(draw.isAction())) { + if(!(draw.isAction(currentPlayer))) { break; } } @@ -3206,7 +3207,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { Card card = currentPlayer.controlPlayer.ironworks_cardToObtain(context); if (card != null && card.getCost(context) <= 4 && !card.costPotion()) { if (currentPlayer.gainNewCard(card, this.controlCard, context).equals(card)) { - if (card.isAction()) { + if (card.isAction(currentPlayer)) { context.actions++; } if (card instanceof TreasureCard) { @@ -3258,7 +3259,7 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { for (Card card : revealedCards) { if (card != null && !card.equals(Cards.curse)) { - if (card.isAction()) { + if (card.isAction(nextPlayer)) { context.actions += 2; } if (card instanceof TreasureCard) { @@ -3774,7 +3775,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { currentPlayer.reveal(draw, this.controlCard, context); - if (draw.isAction() && !draw.equals(Cards.golem)) { + if (draw.isAction(currentPlayer) && !draw.equals(Cards.golem)) { toOrder.add(draw); // currentPlayer.hand.add(draw); } else { @@ -3859,7 +3860,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { } boolean shouldKeep = true; - if (draw.isAction()) { + if (draw.isAction(currentPlayer)) { shouldKeep = currentPlayer.controlPlayer.library_shouldKeepAction(context, (ActionCard) draw); } @@ -4626,7 +4627,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { case TrashActionCard: Card toTrash = currentPlayer.controlPlayer.graverobber_cardToTrash(context); - if (toTrash == null || !currentPlayer.hand.contains(toTrash) || !(toTrash.isAction())) { + if (toTrash == null || !currentPlayer.hand.contains(toTrash) || !(toTrash.isAction(currentPlayer))) { Util.playerError(currentPlayer, "Graverobber trash error, trashing nothing."); return; } @@ -4654,7 +4655,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { currentPlayer.putOnTopOfDeck(card, context, true); } - if (card.isAction()) { + if (card.isAction(currentPlayer)) { context.actions += 1; } if (card instanceof TreasureCard) { @@ -4792,7 +4793,7 @@ private void wanderingMinstrel(Player currentPlayer, MoveContext context) { if (card == null) { break; } - if (!(card.isAction()) ) { + if (!(card.isAction(currentPlayer)) ) { currentPlayer.discard(card, this.controlCard, context); } else { currentPlayer.reveal(card, this.controlCard, context); @@ -5540,7 +5541,7 @@ private void bandOfMisfits(Game game, MoveContext context, Player currentPlayer) if (cardToImpersonate != null && !game.isPileEmpty(cardToImpersonate) && Cards.isSupplyCard(cardToImpersonate) - && cardToImpersonate.isAction() + && cardToImpersonate.isAction(null) && cardToImpersonate.getCost(context) < this.controlCard.getCost(context) && (context.golemInEffect == 0 || cardToImpersonate != Cards.golem)) { GameEvent event = new GameEvent(GameEvent.Type.CardNamed, (MoveContext) context); @@ -5990,7 +5991,7 @@ private void herald(Game game, MoveContext context, Player currentPlayer) { currentPlayer.reveal(draw, this.controlCard, context); - if (draw.isAction()) + if (draw.isAction(currentPlayer)) { context.freeActionInEffect++; ((ActionCardImpl) draw).play(game, context, false); @@ -6229,7 +6230,7 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) } else { currentPlayer.putOnTopOfDeck(c, context, true); } - if ((c instanceof VictoryCard) || (c.isAction())) { + if ((c instanceof VictoryCard) || (c.isAction(currentPlayer))) { currentPlayer.gainNewCard(Cards.magpie, this.controlCard, context); } } diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 002d6ed35..cac3386a3 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -55,7 +55,7 @@ public void gameEvent(GameEvent event) { reactedSet.clear(); } if(event.getPlayer() == this && (event.getType() == GameEvent.Type.CardObtained || event.getType() == GameEvent.Type.BuyingCard)) { - if(event.getCard().isAction()) { + if(event.getCard().isAction(event.getPlayer())) { actionCardCount++; } @@ -336,7 +336,7 @@ public Card[] lowestCards(MoveContext context, ArrayList cards, int num, b } for (int i = cardArray.size() - 1; i >= 0; i--) { Card card = cardArray.get(i); - if (isOnlyVictory(card)) { + if (isOnlyVictory(card, context.getPlayer())) { ret.add(card); cardArray.remove(i); if (ret.size() == num) { @@ -556,7 +556,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { int bestAction = -1; boolean removed = false; for (int i = 0; i < keepers.size(); i++) { - if (keepers.get(i).isAction()) { + if (keepers.get(i).isAction(context.player)) { if (bestAction == -1) { bestAction = i; } else { @@ -676,10 +676,10 @@ public Card[] chapel_cardsToTrash(MoveContext context) { public Card[] cellar_cardsToDiscard(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (context.getActionsLeft() == 0 && card.isAction()) { + if (context.getActionsLeft() == 0 && card.isAction(context.player)) { cards.add(card); } - else if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.copper)) { + else if ((!(card.isAction(context.player)) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.copper)) { cards.add(card); } else if (shouldDiscard(card, context.player)) { @@ -699,7 +699,7 @@ public boolean library_shouldKeepAction(MoveContext context, ActionCard action) return false; } for (Card card : context.getPlayer().getHand()) { - if (card.isAction() && !card.isRuins(context.player)) { + if (card.isAction(context.player) && !card.isRuins(context.player)) { return false; } } @@ -710,7 +710,7 @@ public boolean library_shouldKeepAction(MoveContext context, ActionCard action) @Override public boolean spy_shouldDiscard(MoveContext context, Player targetPlayer, Card card) { boolean ret; - if ( isOnlyVictory(card) + if ( isOnlyVictory(card, targetPlayer) || card.equals(Cards.copper) || card.equals(Cards.curse) || card.isShelter() @@ -948,7 +948,7 @@ public NoblesOption nobles_chooseOptions(MoveContext context) { int actionCards = 0; for (Card card : context.getPlayer().getHand()) { - if ((card.isAction())) { + if ((card.isAction(context.player))) { actionCards++; } } @@ -1120,7 +1120,7 @@ public Card smugglers_cardToObtain(MoveContext context) { @Override public Card island_cardToSetAside(MoveContext context) { for (Card card : context.getPlayer().getHand()) { - if (isOnlyVictory(card)) { + if (isOnlyVictory(card, context.getPlayer())) { return card; } } @@ -1151,7 +1151,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis ArrayList randList = new ArrayList(); int maxCost = -1; for (Card card : cardList) { - if (card.isAction() && card.getCost(context) <= 4 && !card.costPotion()) { + if (card.isAction(context.player) && card.getCost(context) <= 4 && !card.costPotion()) { if ( !card.isRuins(context.player) && !card.equals(Cards.necropolis) && !((ActionCard) card).trashForced() @@ -1322,7 +1322,7 @@ public int ambassador_returnToSupplyFromHand(MoveContext context, Card card) { @Override public boolean pearlDiver_shouldMoveToTop(MoveContext context, Card card) { - if (isOnlyVictory(card) || card.equals(Cards.curse) || card.equals(Cards.copper)) { + if (isOnlyVictory(card, context.getPlayer()) || card.equals(Cards.curse) || card.equals(Cards.copper)) { return false; } @@ -1521,7 +1521,7 @@ public Card contraband_cardPlayerCantBuy(MoveContext context) { public ActionCard kingsCourt_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { - if(c.isAction()) { + if(c.isAction(context.getPlayer())) { return (ActionCard) c; } } @@ -1549,7 +1549,7 @@ public boolean loan_shouldTrashTreasure(MoveContext context, TreasureCard treasu @Override public boolean royalSealTravellingFair_shouldPutCardOnDeck(MoveContext context, Card responsible, Card card) { - if(isOnlyVictory(card)) { + if(isOnlyVictory(card, context.getPlayer())) { return false; } @@ -1562,7 +1562,7 @@ public WatchTowerOption watchTower_chooseOption(MoveContext context, Card card) return WatchTowerOption.Trash; } - if(isOnlyVictory(card) || card.equals(Cards.copper)) { + if(isOnlyVictory(card, context.getPlayer()) || card.equals(Cards.copper)) { return WatchTowerOption.Normal; } @@ -1649,7 +1649,7 @@ public ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards) { public Card hamlet_cardToDiscardForAction(MoveContext context) { int actionCards = 0; for (Card c : context.getPlayer().getHand()) { - if(c.isAction()) { + if(c.isAction(context.getPlayer())) { actionCards++; } } @@ -1701,7 +1701,7 @@ public Card remake_cardToTrash(MoveContext context) { if(c == null) { for (Card check : context.getPlayer().getHand()) { - if(isOnlyVictory(check)) + if(isOnlyVictory(check, context.getPlayer())) continue; Card best = bestCardInPlay(context, check.getCost(context) + 1, false); @@ -1782,21 +1782,21 @@ public VictoryCard bureaucrat_cardToReplace(MoveContext context) { int actions = 0; for (Card card : cards) { - if (card.isAction()) { + if (card.isAction(context.player)) { actions++; } } if(actions > 1) { for (Card card : cards) { - if (card instanceof VictoryCard && !isOnlyVictory(card)) { + if (card instanceof VictoryCard && !isOnlyVictory(card, context.player)) { return (VictoryCard) card; } } } for (Card card : cards) { - if (card instanceof VictoryCard && isOnlyVictory(card)) { + if (card instanceof VictoryCard && isOnlyVictory(card, context.player)) { return (VictoryCard) card; } } @@ -1877,12 +1877,12 @@ public VictoryCard getBestVictoryCard(MoveContext context, VictoryCard[] cards) } return cards[index]; } - public boolean isOnlyTreasure(Card card) { + public boolean isOnlyTreasure(Card card, Player player) { if(!(card instanceof TreasureCard)) { return false; } - if(card.isAction() || card instanceof VictoryCard) { + if(card.isAction(player) || card instanceof VictoryCard) { return false; } @@ -1899,12 +1899,12 @@ public boolean isTrashCard(Card card) { return false; } - public boolean isOnlyVictory(Card card) { + public boolean isOnlyVictory(Card card, Player player) { if(!(card instanceof VictoryCard)) { return false; } - if(card.isAction() || card instanceof TreasureCard) { + if(card.isAction(player) || card instanceof TreasureCard) { return false; } @@ -1916,7 +1916,7 @@ public boolean isCurse(Card card) { } public boolean shouldDiscard(Card card, Player player) { - return isCurse(card) || isOnlyVictory(card) || card.isShelter() || card.isRuins(player); + return isCurse(card) || isOnlyVictory(card, player) || card.isShelter() || card.isRuins(player); } public boolean shouldBuyPotion() { @@ -1937,7 +1937,7 @@ public boolean duchess_shouldDiscardCardFromTopOfDeck(MoveContext context, Card if(isTrashCard(card)) { return true; } - if(isOnlyVictory(card)) { + if(isOnlyVictory(card, context.getPlayer())) { return true; } return false; @@ -1989,7 +1989,7 @@ public TreasureCard nobleBrigand_silverOrGoldToTrash(MoveContext context, Treasu @Override public boolean jackOfAllTrades_shouldDiscardCardFromTopOfDeck(MoveContext context, Card card) { - if(isOnlyVictory(card)) { + if(isOnlyVictory(card, context.getPlayer())) { return true; } if(isTrashCard(card) && (jackOfAllTrades_nonTreasureToTrash(context) != null || (card instanceof TreasureCard))) { @@ -2040,7 +2040,7 @@ public Card[] embassy_cardsToDiscard(MoveContext context) { public Card[] cartographer_cardsFromTopOfDeckToDiscard(MoveContext context, Card[] cards) { ArrayList cardsToDiscard = new ArrayList(); for(Card card : cards) { - if(isTrashCard(card) || isOnlyVictory(card)) { + if(isTrashCard(card) || isOnlyVictory(card, context.getPlayer())) { cardsToDiscard.add(card); } } @@ -2114,7 +2114,7 @@ public boolean oracle_shouldDiscard(MoveContext context, Player player, ArrayLis copper = true; } - if(isTrashCard(c) || isOnlyVictory(c)) { + if(isTrashCard(c) || isOnlyVictory(c, player)) { discard = false; } else if( c.getCost(null) >= 5 @@ -2218,7 +2218,7 @@ public TreasureCard stables_treasureToDiscard(MoveContext context) { public Card mandarin_cardToReplace(MoveContext context) { if (context.getActionsLeft() == 0) { for (Card card : context.getPlayer().getHand()) { - if (card.isAction()) { + if (card.isAction(context.getPlayer())) { return card; } } @@ -2378,7 +2378,7 @@ public Card deathCart_actionToTrash(MoveContext context) } for (Card c : context.player.hand) { - if (c.isAction() && c.getCost(context) <= Cards.deathCart.getCost(context)) { + if (c.isAction(context.player) && c.getCost(context) <= Cards.deathCart.getCost(context)) { return c; } } @@ -2418,8 +2418,8 @@ public Card graverobber_cardToGainFromTrash(MoveContext context) { @Override public Card graverobber_cardToTrash(MoveContext context) { CardList ac = new CardList(controlPlayer, getPlayerName(false)); - for (Card c : hand) { - if (c.isAction()) { + for (Card c : context.getPlayer().getHand()) { + if (c.isAction(context.getPlayer())) { ac.add(c); } } @@ -2491,14 +2491,14 @@ public Card scavenger_cardToPutBackOnDeck(MoveContext context) { public Card[] storeroom_cardsToDiscardForCards(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { + if ((!(card.isAction(context.getPlayer())) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { cards.add(card); } } if (context.getActionsLeft() == 0) { for (Card c : context.getPlayer().getHand()) { - if ((c.isAction())) { + if ((c.isAction(context.getPlayer()))) { cards.add(c); } } @@ -2511,14 +2511,14 @@ public Card[] storeroom_cardsToDiscardForCards(MoveContext context) { public Card[] storeroom_cardsToDiscardForCoins(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if ((!(card.isAction()) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { + if ((!(card.isAction(context.getPlayer())) && !(card instanceof TreasureCard)) || card.equals(Cards.cellar) || card.equals(Cards.storeroom) || card.equals(Cards.copper)) { cards.add(card); } } if (context.getActionsLeft() == 0) { for (Card c : context.getPlayer().getHand()) { - if ((c.isAction())) { + if ((c.isAction(context.getPlayer()))) { cards.add(c); } } @@ -2610,7 +2610,7 @@ public Card pillage_opponentCardToDiscard(MoveContext context, ArrayList h ArrayList goodCards = new ArrayList(); for (Card c : handCards) - if (c instanceof TreasureCard || c.isAction()) + if (c instanceof TreasureCard || c.isAction(context.getPlayer())) goodCards.add(c); if (goodCards.size() > 0) { @@ -2651,7 +2651,7 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { boolean containsCopper = false; CardList cl = new CardList(context.getPlayer(), context.getPlayer().getPlayerName()); for(Card card : cards) { - if (!isOnlyVictory(card) && !isCurse(card) && !isTrashCard(card) && !(context.actions == 0 && (card.isAction()))) { + if (!isOnlyVictory(card, context.getPlayer()) && !isCurse(card) && !isTrashCard(card) && !(context.actions == 0 && (card.isAction(context.getPlayer())))) { cl.add(card); } if (card.equals(Cards.copper)) { @@ -2783,7 +2783,7 @@ public Card[] urchin_attack_cardsToKeep(MoveContext context) int bestAction = -1; boolean removed = false; for (int i = 0; i < keepers.size(); i++) { - if (keepers.get(i).isAction()) { + if (keepers.get(i).isAction(context.getPlayer())) { if (bestAction == -1) { bestAction = i; } else { @@ -2866,11 +2866,11 @@ public Card hermit_cardToTrash(MoveContext context, ArrayList cardList, in { CardList cl = new CardList(controlPlayer, getPlayerName(false)); for (Card c : cardList) { - if (c.isAction()) { + if (c.isAction(context.getPlayer())) { cl.add(c); } } - return pickOutCard(cl, getTrashCards()); + return pickOutCard(cl, getTrashCards()); } @Override @@ -3254,7 +3254,7 @@ public CallableCard call_whenActionResolveCardToCall(MoveContext context, Action // Check coin of the Realm first boolean hasMoreActionsLeft = false; for (Card c : getHand()) { - if (c.isAction()) { + if (c.isAction(context.getPlayer())) { hasMoreActionsLeft = true; } } @@ -3344,7 +3344,7 @@ private Card getBestActionCard(CardList hand, MoveContext context) { int highestCost = -1; Card bestCard = null; for (Card c : getDistinctCards()) { - if (c.isAction()) { + if (c.isAction(context.getPlayer())) { int cost = c.getCost(context); if (cost > highestCost) { highestCost = cost; @@ -3359,7 +3359,7 @@ private Card getBestActionCard(CardList hand, MoveContext context) { public ActionCard disciple_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { - if(c.isAction()) { + if(c.isAction(context.getPlayer())) { return (ActionCard) c; } } @@ -3375,7 +3375,7 @@ public Card fugitive_cardToDiscard(MoveContext context) { public Card[] gear_cardsToSetAside(MoveContext context) { ArrayList cards = new ArrayList(); for (Card card : context.getPlayer().getHand()) { - if (context.getActionsLeft() == 0 && card.isAction()) { + if (context.getActionsLeft() == 0 && card.isAction(context.getPlayer())) { cards.add(card); } } @@ -3479,7 +3479,7 @@ public Card raze_cardToKeep(MoveContext context, Card[] cards) { ArrayList goodCards = new ArrayList(); for (Card c : cards) - if (c instanceof TreasureCard || c.isAction()) + if (c instanceof TreasureCard || c.isAction(context.getPlayer())) goodCards.add(c); if (goodCards.size() > 0) { @@ -3533,7 +3533,7 @@ public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerS Card[] cards = context.game.getCardsInGame(); Arrays.sort(cards, new Util.CardCostComparatorDesc()); for (Card c : cards) { - if (c.isAction() && + if (c.isAction(null) && Cards.isSupplyCard(c) && game.getPlayerSupplyTokens(c, this).size() == 0) return (ActionCard) c; @@ -3715,7 +3715,7 @@ public Card save_cardToSetAside(MoveContext context) { float potionUtility = 2.5f; for (Card c : context.getPlayer().getHand()) { float utility = c.getCost(context) + (c.costPotion() ? potionUtility : 0); - if (isOnlyVictory(c)) + if (isOnlyVictory(c, context.getPlayer())) utility = -2; if (c.equals(Cards.curse)) utility = -1; diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 3ecfe1322..29c083a42 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -242,7 +242,7 @@ private void teacher(MoveContext context, Game game, Player currentPlayer) { ActionCard lastFreePile = null; for (Card c : game.getCardsInGame()) { if (game.getPile(c).isSupply() - && c.isAction() + && c.isAction(null) && game.getPlayerSupplyTokens(c, currentPlayer).size() == 0) { numFreePiles++; lastFreePile = (ActionCard) c; diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 62ffa0c10..391eccbe0 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -233,7 +233,8 @@ public int getCost(MoveContext context, boolean buyPhase) { return context.game.getTopKnightCard().getCost(context,buyPhase); int costModifier = 0; - costModifier -= this.isAction() ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; + //TODO: BUG this isAction call for Quarry should be player-specific sometimes + costModifier -= this.isAction(null) ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; costModifier -= context.countCardsInPlay(Cards.highway); costModifier -= context.countCardsInPlay(Cards.bridgeTroll); costModifier -= context.countCardsInNextTurn(Cards.bridgeTroll); @@ -367,10 +368,6 @@ public boolean costPotion() { return costPotion; } - public boolean isAction() { - return this instanceof ActionCard; - } - @Override public boolean isDuration(Player player) { if (player == null || player.getInheritance() == null) @@ -380,8 +377,9 @@ public boolean isDuration(Player player) { @Override public boolean isAction(Player player) { - //TODO: redo? - return player.getInheritance() != null && this.getType() == player.getInheritance().getType(); + if (player == null || player.getInheritance() == null) + return this instanceof ActionCard; + return player.getInheritance() instanceof ActionCard; } @Override diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index ece0e2005..8bd85e614 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1429,7 +1429,7 @@ public boolean isValidAction(MoveContext context, Card action) { return false; } - if (!(action.isAction())) { + if (!(action.isAction(context.player))) { return false; } @@ -2707,7 +2707,7 @@ public void gameEvent(GameEvent event) { int actionCardsFound = 0; for(int i=player.discard.size() - 1; i >= 0; i--) { Card c = player.discard.get(i); - if(c.isAction()) { + if(c.isAction(player)) { actionCardsFound++; if(player.controlPlayer.inn_shuffleCardBackIntoDeck(event.getContext(), (ActionCard) c)) { cards.add(c); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 403fb6732..05ad94173 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -219,7 +219,7 @@ private Card[] doAction(MoveContext context, boolean singleCard) { int actionCount = 0; Card actionCard = null; for (Card card : (context.player.isPossessed()) ? context.player.getHand() : getHand()) { - if (card.isAction()) { + if (card.isAction(context.player)) { actionCount++; actionCard = card; } diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index ed75ad0d6..1eaec2a68 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -164,7 +164,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { for (Card c : getPlayedCards()) { if ((type == CardsInPlay.ATTACK && c.isAttack(player)) || (type == CardsInPlay.TRAVELLER && c.isTraveller(player)) - || (type == CardsInPlay.ACTION && c.isAction())) { + || (type == CardsInPlay.ACTION && c.isAction(player))) { actionsInPlay++; } } @@ -173,7 +173,7 @@ public int countActionAttackTravellerCardsInPlayThisTurn(CardsInPlay type) { continue; if ((type == CardsInPlay.ATTACK && c.isAttack(player)) || (type == CardsInPlay.TRAVELLER && c.isTraveller(player)) - || (type == CardsInPlay.ACTION && c.isAction())) { + || (type == CardsInPlay.ACTION && c.isAction(player))) { actionsInPlay++; } } @@ -280,7 +280,7 @@ public GameType getGameType() { } public boolean canPlay(Card card) { - if (card.isAction()) { + if (card.isAction(player)) { return game.isValidAction(this, card); } else { return false; diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 63c8b88b0..38cf55774 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -113,10 +113,10 @@ public void newTurn() { turnCount++; } - public ArrayList getActionCards(Card[] cards) { + public ArrayList getActionCards(Card[] cards, Player player) { ArrayList actionCards = new ArrayList(); for (Card card : cards) { - if (card.isAction()) { + if (card.isAction(player)) { actionCards.add(card); } } @@ -124,14 +124,14 @@ public ArrayList getActionCards(Card[] cards) { return actionCards; } - public int getActionCardCount(Card[] cards) { - return getActionCards(cards).size(); + public int getActionCardCount(Card[] cards, Player player) { + return getActionCards(cards, player).size(); } public int getMyAddActionCardCount() { int addActionsCards = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(this)) { if (((ActionCard) card).getAddActions() > 0) { addActionsCards++; } @@ -144,7 +144,7 @@ public int getMyAddActionCardCount() { public int getMyAddCardCardCount() { int addCards = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(this)) { if (((ActionCard) card).getAddCards() > 0) { addCards++; } @@ -157,7 +157,7 @@ public int getMyAddCardCardCount() { public int getMyAddActions() { int addActions = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(this)) { addActions += ((ActionCard) card).getAddActions(); } } @@ -168,7 +168,7 @@ public int getMyAddActions() { public int getMyAddCards() { int addCards = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(this)) { addCards += ((ActionCard) card).getAddCards(); } } @@ -179,7 +179,7 @@ public int getMyAddCards() { public int getMyAddBuys() { int addBuys = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(this)) { addBuys += ((ActionCard) card).getAddBuys(); } } @@ -396,7 +396,7 @@ protected void cleanup(MoveContext context) { context.schemesPlayed --; ArrayList actions = new ArrayList(); for(Card c : playedCards) { - if(c.isAction()) { + if(c.isAction(context.player)) { actions.add(c); } } @@ -735,14 +735,14 @@ public int getCardCount(final Class cardClass, ArrayList cards) { return cardCount; } - public int getActionCardCount() { - return getActionCardCount(getAllCards()); + public int getActionCardCount(Player player) { + return getActionCardCount(getAllCards(), player); } - public int getActionCardCount(ArrayList cards) { + public int getActionCardCount(ArrayList cards, Player player) { int cardCount = 0; for (Card c : cards) { - if (c.isAction()) { + if (c.isAction(player)) { cardCount++; } } @@ -813,7 +813,7 @@ public Map getVictoryPointTotals(Map counts) { if(counts.containsKey(Cards.fairgrounds)) totals.put(Cards.fairgrounds, counts.get(Cards.fairgrounds) * ((counts.get(DISTINCT_CARDS) / 5) * 2)); if(counts.containsKey(Cards.vineyard)) - totals.put(Cards.vineyard, counts.get(Cards.vineyard) * (this.getActionCardCount() / 3)); + totals.put(Cards.vineyard, counts.get(Cards.vineyard) * (this.getActionCardCount(this) / 3)); if(counts.containsKey(Cards.silkRoad)) totals.put(Cards.silkRoad, counts.get(Cards.silkRoad) * (this.getVictoryCardCount() / 4)); if(counts.containsKey(Cards.feodum)) @@ -1400,11 +1400,11 @@ public ArrayList getVictoryInHand() { return victory; } - public ArrayList getActionsInHand() { + public ArrayList getActionsInHand(Player player) { ArrayList actions = new ArrayList(); for (Card c : getHand()) - if (c.isAction()) + if (c.isAction(player)) actions.add((ActionCard) c); return actions; diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index dc4983f42..37c8d17d8 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -493,7 +493,7 @@ public boolean shouldAutoPlay_hamlet_cardToDiscardForAction(MoveContext context) int actionCards = 0; int trashCards = 0; for(Card c : getHand()) { - if(c.isAction()) { + if(c.isAction(context.player)) { actionCards++; } for(Card trash : getTrashCards()) { @@ -609,7 +609,7 @@ public boolean shouldAutoPlay_duchess_shouldDiscardCardFromTopOfDeck(MoveContext return true; } } - if(isOnlyVictory(card)) { + if(isOnlyVictory(card, context.getPlayer())) { return true; } @@ -634,7 +634,7 @@ public boolean shouldAutoPlay_trader_cardToTrash(MoveContext context) { public boolean shouldAutoPlay_oasis_cardToDiscard(MoveContext context) { for(Card c : getHand()) { - if(isTrashCard(c) || isOnlyTreasure(c)) { + if(isTrashCard(c) || isOnlyTreasure(c, context.player)) { return true; } } @@ -643,7 +643,7 @@ public boolean shouldAutoPlay_oasis_cardToDiscard(MoveContext context) { } public boolean shouldAutoPlay_jackOfAllTrades_shouldDiscardCardFromTopOfDeck(MoveContext context, Card card) { - if(isTrashCard(card) || isOnlyVictory(card)) { + if(isTrashCard(card) || isOnlyVictory(card, context.getPlayer())) { return true; } return false; diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index 1ac5fd914..d165b54ac 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -650,13 +650,13 @@ public int compare(Card card0, Card card1) { static public class CardTypeComparator implements Comparator { @Override public int compare(Card card0, Card card1) { - if(card0.isAction()) { - if(card1.isAction()) { + if(card0.isAction(null)) { + if(card1.isAction(null)) { return 0; } else { return -1; } - } else if(card1.isAction()) { + } else if(card1.isAction(null)) { return 1; } else if(card0 instanceof TreasureCard || card0.getType() == Type.Potion) { if(card1 instanceof TreasureCard || card1.getType() == Type.Potion) { diff --git a/vdom/src/com/vdom/core/VariableCardPile.java b/vdom/src/com/vdom/core/VariableCardPile.java index e0ef825b7..bf8153e5d 100644 --- a/vdom/src/com/vdom/core/VariableCardPile.java +++ b/vdom/src/com/vdom/core/VariableCardPile.java @@ -56,7 +56,7 @@ public void addLinkedPile(SingleCardPile p) { @Override public void addCard(Card card) { - if (!card.isAction()) return; + if (!card.isAction(null)) return; piles.get(card.getName()).addCard(card); diff --git a/vdom/src/com/vdom/players/VDomPlayerChuck.java b/vdom/src/com/vdom/players/VDomPlayerChuck.java index 014c7a429..d561a4b98 100644 --- a/vdom/src/com/vdom/players/VDomPlayerChuck.java +++ b/vdom/src/com/vdom/players/VDomPlayerChuck.java @@ -216,12 +216,12 @@ public Card doBuy(MoveContext context) { card.equals(Cards.throneRoom) && throneRoomAndKingsCourtCount >= 2 || card.equals(Cards.disciple) && throneRoomAndKingsCourtCount >= 2 || card.equals(Cards.kingsCourt) && throneRoomAndKingsCourtCount >= 2 || - !(card.isAction()) && !(card instanceof TreasureCard) + !(card.isAction(context.getPlayer())) && !(card instanceof TreasureCard) ) { continue; } - if (card.isAction() && actionCardCount >= ACTION_CARDS_MAX) { + if (card.isAction(context.getPlayer()) && actionCardCount >= ACTION_CARDS_MAX) { continue; } diff --git a/vdom/src/com/vdom/players/VDomPlayerEarl.java b/vdom/src/com/vdom/players/VDomPlayerEarl.java index df9a2a0d3..5ba4e4f04 100644 --- a/vdom/src/com/vdom/players/VDomPlayerEarl.java +++ b/vdom/src/com/vdom/players/VDomPlayerEarl.java @@ -161,7 +161,7 @@ private void calculateStats(ArrayList historyItems) { HashMap victoryHelpers = getVictoryStat(historyItems); for (HistoryItem historyItem : historyItems) { - if ((historyItem.getAction() == HistoryItem.Action.BOUGHT) && (historyItem.getCard().isAction())) { + if ((historyItem.getAction() == HistoryItem.Action.BOUGHT) && (historyItem.getCard().isAction(this))) { debug(historyItem.toString() + ", was in hand " + inHand.get(historyItem.getCard().getId()) + " times, played " + played.get(historyItem.getCard().getId()) + " times, and saw " + victoryHelpers.get(historyItem.getCard().getId()) + " vps"); } @@ -211,7 +211,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe int actionCards = 0; for (Card card : hand) { - if ( card.isAction() + if ( card.isAction(context.player) && !card.equals(Cards.rats) && !(card.equals(Cards.tactician) && context.countCardsInPlay(Cards.tactician) > 0) ) { @@ -274,7 +274,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe return Cards.throneRoom; } - Card bestCard = getBestAddingAction(hasThroneRoom); + Card bestCard = getBestAddingAction(hasThroneRoom, context.player); if (bestCard != null) { return Cards.throneRoom; } @@ -287,7 +287,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe THRONE_ROOM_DUDS += 1; } - Card bestCard = getBestAddingAction(hasThroneRoom); + Card bestCard = getBestAddingAction(hasThroneRoom, context.player); if (bestCard != null) { return bestCard; } @@ -320,7 +320,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe if (card.equals(Cards.treasureMap)) { continue; } - if (card.isAction()) { + if (card.isAction(context.player)) { if (dontPlay.contains(card)) { continue; } @@ -334,12 +334,12 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe return null; } - private ActionCard getBestAddActionAction(Card[] hand) { + private ActionCard getBestAddActionAction(Card[] hand, Player player) { ActionCard bestAction = null; int bestAddActions = 0; for (Card card : hand) { - if (card.isAction()) { + if (card.isAction(player)) { ActionCard action = (ActionCard)card; if (action.getAddActions() > 0) { int addCards = action.getAddCards(); @@ -357,12 +357,12 @@ private ActionCard getBestAddActionAction(Card[] hand) { return bestAction; } - private ActionCard getBestAddActionCard(Card[] hand) { + private ActionCard getBestAddActionCard(Card[] hand, Player player) { ActionCard bestAction = null; int bestAddCards = 0; for (Card card : hand) { - if (card.isAction()) { + if (card.isAction(player)) { ActionCard action = (ActionCard)card; int thisAddCards = action.getAddCards(); if (thisAddCards > bestAddCards) { @@ -375,13 +375,13 @@ private ActionCard getBestAddActionCard(Card[] hand) { return bestAction; } - private Card getBestAddingAction(boolean hasThroneRoom) { + private Card getBestAddingAction(boolean hasThroneRoom, Player player) { Card[] hand = getHand().toArray(); - Card bestAction = getBestAddActionAction(hand); + Card bestAction = getBestAddActionAction(hand, player); if (bestAction == null) { - bestAction = getBestAddActionCard(hand); + bestAction = getBestAddActionCard(hand, player); } if (bestAction != null) { @@ -998,13 +998,13 @@ public Card masquerade_cardToPass(MoveContext context) return c; } - private int nonNobleActionCardCount() { + private int nonNobleActionCardCount(Player player) { int count = 0; for (Card card : getHand()) { if (card.equals(Cards.nobles)) { continue; } - if (card.isAction()) { + if (card.isAction(player)) { ++count; } } @@ -1020,7 +1020,7 @@ public Player.NoblesOption nobles_chooseOptions(MoveContext context) return Player.NoblesOption.AddCards; if (inHandCount(Cards.nobles) == 2) return Player.NoblesOption.AddActions; - if (nonNobleActionCardCount() > 0) { + if (nonNobleActionCardCount(context.player) > 0) { return Player.NoblesOption.AddActions; } return Player.NoblesOption.AddCards; diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index 018c7dde4..6c0ef63be 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -420,7 +420,7 @@ private void log(String s) { - private boolean isCantrip(ActionCard card) { + private boolean isCantrip(Card card) { if (card == null) { return false; } @@ -435,7 +435,7 @@ private boolean isCantrip(ActionCard card) { @Override public Card doAction(MoveContext context) { - return this.advisorPlayAction(this.hand.toArrayListClone()); + return this.advisorPlayAction(this.hand.toArrayListClone(), context.player); } private int getCardsToEndGame() { @@ -575,9 +575,7 @@ private int getCurrencyTotal(ArrayList list) { money += (list.size()-7) / 5; } - if (card.isAction()) { - money += ((ActionCard) card).getAddGold(); - } + money += card.getAddGold(); } if (Util.getCardCount(list, Cards.foolsGold) > 1) { @@ -604,11 +602,8 @@ private int guessCurrencyTotal(ArrayList list) { if (card instanceof TreasureCard) { money += ((TreasureCard) card).getValue(); } - if (card.isAction()) { - ActionCard ac = (ActionCard)card; - money += ac.getAddGold(); - //money += ac.getAddCards(); - } + money += card.getAddGold(); + if (card.equals(Cards.venture)) { //TODO maybe there is some way of incorporating the avg money per card without creating an infinite loop? money += 1; @@ -642,7 +637,7 @@ private int guessCurrencyTotal(ArrayList list) { * @param list list of cards * @return amount of VPs provided by the cards */ - private int getVPTotalValue (ArrayList list) { + private int getVPTotalValue (ArrayList list, Player player) { int vps = this.getVictoryTokens(); for (Card card : list) { @@ -659,7 +654,7 @@ private int getVPTotalValue (ArrayList list) { vps += list.size() / 10; } if (card.equals(Cards.vineyard)) { - vps += Math.round(this.getActionCardCount(list) / 3); + vps += Math.round(this.getActionCardCount(list, player) / 3); } if (card.equals(Cards.fairgrounds)) { vps += Math.round(this.getCardNameCount(list) / 5); @@ -716,7 +711,7 @@ private double getMoneyPerCard(ArrayList list, int plustreasure, int plusc * @return best candidate for discarding */ @SuppressWarnings("unchecked") - private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { + private Card getCardToDiscard(ArrayList list, DiscardOption destructive, Player player) { // Tunnel if (list.contains(Cards.tunnel)) { return list.get(list.indexOf(Cards.tunnel)); @@ -747,7 +742,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { // Victory cards with no other function for (Card card : list) { - if (isOnlyVictory(card)) { + if (isOnlyVictory(card, player)) { return card; } } @@ -760,7 +755,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { switch (this.strategy) { case NoAction: for (Card card : list) { - if (card.isAction()) { + if (card.isAction(this)) { return card; } } @@ -782,7 +777,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { { StrategyOption saveStrategy = this.strategy; this.strategy = StrategyOption.Nothing; - Card card = getCardToDiscard(cards2discard, destructive); + Card card = getCardToDiscard(cards2discard, destructive, player); this.strategy = saveStrategy; return card; } @@ -820,7 +815,7 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { // Action cards for (Card card : list) { - if (card.isAction()) { + if (card.isAction(this)) { return card; } } @@ -874,13 +869,13 @@ private Card getCardToDiscard(ArrayList list, DiscardOption destructive) { * @param destructive discard is mandatory? * @return list of cards that can be discarded */ - private ArrayList getCardsToDiscard(ArrayList list, int number, DiscardOption destructive) { + private ArrayList getCardsToDiscard(ArrayList list, int number, DiscardOption destructive, Player player) { ArrayList ret = new ArrayList(); int discarded = 0; Card dcard = null; while ((!list.isEmpty()) && (discarded < number)) { - dcard = this.getCardToDiscard(list, destructive); + dcard = this.getCardToDiscard(list, destructive, player); if (dcard != null) { ret.add(discarded, dcard); list.remove(ret.get(discarded)); @@ -1011,7 +1006,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { Card card2discard = null; while (cards2keep.size() > 3) { - card2discard = getCardToDiscard(cards2keep, DiscardOption.Destructive); + card2discard = getCardToDiscard(cards2keep, DiscardOption.Destructive, context.getPlayer()); cards2keep.remove(card2discard); } @@ -1027,7 +1022,7 @@ public Card saboteur_cardToObtain(MoveContext context, int maxCost, boolean poti @Override public Card[] torturer_attack_cardsToDiscard(MoveContext context) { //TODO test - return this.getCardsToDiscard(this.hand.toArrayListClone(), 2, DiscardOption.Destructive).toArray(new Card[2]); + return this.getCardsToDiscard(this.hand.toArrayListClone(), 2, DiscardOption.Destructive, context.getPlayer()).toArray(new Card[2]); } @Override @@ -1038,7 +1033,7 @@ public Card[] vault_cardsToDiscardForGold(MoveContext context) { Card card = null; while (ret.size() < 2) { - card = this.getCardToDiscard(temphand, DiscardOption.SemiDestructive); + card = this.getCardToDiscard(temphand, DiscardOption.SemiDestructive, context.getPlayer()); if (card == null) { break; } @@ -1049,7 +1044,7 @@ public Card[] vault_cardsToDiscardForGold(MoveContext context) { while (ret.size() < 2) { if (getMyAddActions() == 0) { for (Card acard : temphand) { - if (acard.isAction()) { + if (acard.isAction(context.player)) { ret.add(acard); } } @@ -1133,15 +1128,15 @@ public Card island_cardToSetAside(MoveContext context) { ArrayList temphand = this.hand.toArrayListClone(); while (temphand.size() > 0) { - ret = getCardToDiscard(temphand, DiscardOption.Destructive); + ret = getCardToDiscard(temphand, DiscardOption.Destructive, context.getPlayer()); temphand.remove(ret); - if (this.isOnlyVictory(ret)) { + if (this.isOnlyVictory(ret, context.getPlayer())) { return ret; } } temphand = this.hand.toArrayListClone(); - return getCardToDiscard(temphand, DiscardOption.Destructive); + return getCardToDiscard(temphand, DiscardOption.Destructive, context.getPlayer()); } @Override @@ -1174,7 +1169,7 @@ public TorturerOption torturer_attack_chooseOption(MoveContext context) { ArrayList temphand = this.hand.toArrayListClone(); int discarded = Math.min(2, temphand.size()); - ArrayList toDiscard = this.getCardsToDiscard(temphand, discarded, DiscardOption.SemiDestructive); + ArrayList toDiscard = this.getCardsToDiscard(temphand, discarded, DiscardOption.SemiDestructive, context.getPlayer()); if (toDiscard.size() >= discarded) { return Player.TorturerOption.DiscardTwoCards; } @@ -1233,10 +1228,10 @@ public boolean shouldBuyPotion() { return ret; } - public boolean shouldDiscard(Card card) { + public boolean shouldDiscard(Card card, Player player) { ArrayList c = new ArrayList(); c.add(card); - return (this.getCardToDiscard(c, DiscardOption.NonDestructive) != null); + return (this.getCardToDiscard(c, DiscardOption.NonDestructive, player) != null); } public boolean shouldTrash(Card card) { @@ -1271,7 +1266,7 @@ public boolean loan_shouldTrashTreasure(MoveContext context, TreasureCard treasu * @return amount of VPs in the deck */ private int getVPTotalValue (MoveContext context) { - return this.getVPTotalValue(this.getAllCards()); + return this.getVPTotalValue(this.getAllCards(), context.player); } /** @@ -1697,7 +1692,7 @@ else if (specialTreasureCards.contains(c)) { this.strategyMultiCardTerminal = action_card; this.log("multi action terminal: " + this.strategyMultiCardTerminal); } - if (this.guessCurrencyTotal(getAllCards()) > 7 + this.getActionCardCount()) { + if (this.guessCurrencyTotal(getAllCards()) > 7 + this.getActionCardCount(context.player)) { return action_card; } } @@ -1950,10 +1945,8 @@ private int getDeckSize(ArrayList deck) { int size = 0; for (Card card : deck) { size++; - if (card.isAction()) { - if(isCantrip((ActionCard) card)) { - size--; - } + if(isCantrip(card)) { + size--; } } return size; @@ -1988,7 +1981,7 @@ public Card jackOfAllTrades_nonTreasureToTrash(MoveContext context) { public boolean jackOfAllTrades_shouldDiscardCardFromTopOfDeck(MoveContext context, Card card) { ArrayList a = new ArrayList(); a.add(card); - if( card.equals(getCardToDiscard(a, DiscardOption.NonDestructive)) + if( card.equals(getCardToDiscard(a, DiscardOption.NonDestructive, context.getPlayer())) && (jackOfAllTrades_nonTreasureToTrash(context) != null || (card instanceof TreasureCard))) { return true; } @@ -2021,7 +2014,7 @@ public void gameEvent(GameEvent event) { if ((event.getType() == GameEvent.Type.BuyingCard) || (event.getType() == GameEvent.Type.CardObtained)) { Card card = event.getCard(); - if (card.isAction()) { + if (card.isAction(event.player)) { ActionCard ac = (ActionCard) card; this.opponents.get(event.player.playerNumber).putActionCard(card); if (ac.isAttack(event.player)) { @@ -2081,7 +2074,7 @@ public Card[] chapel_cardsToTrash(MoveContext context) { @Override public Card[] vault_cardsToDiscardForCard(MoveContext context) { - return this.getCardsToDiscard(hand.toArrayListClone(), 2, DiscardOption.SemiDestructive).toArray(new Card[2]); + return this.getCardsToDiscard(hand.toArrayListClone(), 2, DiscardOption.SemiDestructive, context.getPlayer()).toArray(new Card[2]); } @@ -2110,7 +2103,7 @@ public WatchTowerOption watchTower_chooseOption(MoveContext context, Card card) return WatchTowerOption.Trash; } - if(isOnlyVictory(card)) { + if(isOnlyVictory(card, context.getPlayer())) { return WatchTowerOption.Normal; } @@ -2285,7 +2278,7 @@ public Card lookout_cardToDiscard(MoveContext context, Card[] cards) { } this.log("lookout_cardToDiscard: " + temp); - return this.getCardToDiscard(temp, DiscardOption.Destructive); + return this.getCardToDiscard(temp, DiscardOption.Destructive, context.getPlayer()); } @@ -2344,7 +2337,7 @@ private ArrayList getTerminalsInDeck(MoveContext context) { ArrayList ret = new ArrayList(); for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(context.player)) { if (((ActionCard) card).getAddActions() <= 0) { ret.add(card); } @@ -2358,7 +2351,7 @@ private float getCardsPerHand(MoveContext context) { int addcards = 0; for (Card card : getAllCards()) { - if (card.isAction()) { + if (card.isAction(context.player)) { addcards += ((ActionCard) card).getAddCards(); } } @@ -2377,11 +2370,11 @@ public Card haggler_cardToObtain(MoveContext context, int maxCost, boolean potio return this.advisorGeneral(context, maxCost, false, true); } - private Card advisorPlayAction(ArrayList hand) { + private Card advisorPlayAction(ArrayList hand, Player player) { this.log("advisorPlayAction: " + hand); ArrayList ac = new ArrayList(); for (Card card : hand) { - if (card.isAction()) { + if (card.isAction(player)) { ac.add((ActionCard) card); } } @@ -2390,21 +2383,21 @@ private Card advisorPlayAction(ArrayList hand) { if (ac.size() > 0) { if (ac.contains(Cards.kingsCourt)) { temphand.remove(Cards.kingsCourt); - Card temp = advisorPlayAction(temphand); + Card temp = advisorPlayAction(temphand, player); if (temp != null) { return hand.get(hand.indexOf(Cards.kingsCourt)); } } if (ac.contains(Cards.throneRoom)) { temphand.remove(Cards.throneRoom); - Card temp = advisorPlayAction(temphand); + Card temp = advisorPlayAction(temphand, player); if (temp != null) { return hand.get(hand.indexOf(Cards.throneRoom)); } } if (ac.contains(Cards.disciple)) { temphand.remove(Cards.disciple); - Card temp = advisorPlayAction(temphand); + Card temp = advisorPlayAction(temphand, player); if (temp != null) { return hand.get(hand.indexOf(Cards.disciple)); } @@ -2572,7 +2565,7 @@ public Card courtyard_cardToPutBackOnDeck(MoveContext context) { public boolean scryingPool_shouldDiscard(MoveContext context, Player targetPlayer, Card card) { ArrayList c = new ArrayList(); c.add(card); - boolean discard = (this.getCardToDiscard(c, DiscardOption.SemiDestructive) != null); + boolean discard = (this.getCardToDiscard(c, DiscardOption.SemiDestructive, targetPlayer) != null); if (targetPlayer == this) { this.log("scryingPool_shouldDiscard: " + (discard ? "discard " : "keep ") + "my " + card ); @@ -2646,7 +2639,7 @@ public Card ironworks_cardToObtain(MoveContext context) { @Override public boolean duchess_shouldDiscardCardFromTopOfDeck(MoveContext context, Card card) { - return this.shouldDiscard(card); + return this.shouldDiscard(card, context.getPlayer()); } diff --git a/vdom/src/com/vdom/players/VDomPlayerSarah.java b/vdom/src/com/vdom/players/VDomPlayerSarah.java index b59d053a5..93d0a9108 100644 --- a/vdom/src/com/vdom/players/VDomPlayerSarah.java +++ b/vdom/src/com/vdom/players/VDomPlayerSarah.java @@ -374,7 +374,7 @@ public String getPlayerName(boolean maskName) { @Override public Card doAction(MoveContext context) { - ArrayList actionCards = context.getPlayer().getActionsInHand(); + ArrayList actionCards = context.getPlayer().getActionsInHand(context.player); // don't play rats if (game.isCardInGame(Cards.rats)) { @@ -479,7 +479,7 @@ public Card doAction(MoveContext context) { public boolean shouldPassOnBuy(MoveContext context, Card card) { return !context.canBuy(card) || - card.isAction() && actionCardCount >= actionCardMax || + card.isAction(context.player) && actionCardCount >= actionCardMax || !favorSilverGoldPlat && (card.equals(Cards.silver) || card.equals(Cards.masterpiece) || card.equals(Cards.gold) || card.equals(Cards.platinum)) || card.equals(Cards.curse) || card.equals(Cards.virtualRuins) || @@ -490,7 +490,7 @@ public boolean shouldPassOnBuy(MoveContext context, Card card) { card.equals(Cards.disciple) && throneRoomAndKingsCourtCount >= throneRoomsAndKingsCourtsMax || card.equals(Cards.kingsCourt) && throneRoomAndKingsCourtCount >= throneRoomsAndKingsCourtsMax || context.getEmbargosIfCursesLeft(card) > 0 || - !(card.isAction()) && !(card instanceof TreasureCard) && !(card instanceof EventCard); + !(card.isAction(context.player)) && !(card instanceof TreasureCard) && !(card instanceof EventCard); } @Override @@ -683,7 +683,7 @@ public Card bestBuy(int coinAvailableForBuy, MoveContext context, Card[] cards) } final int currentCount = getMyCardCount(card); - if(isOnlyTreasure(card) || card instanceof VictoryCard || currentCount == 0 || rand.nextInt(MAX_OF_ONE_ACTION_CARD) < currentCount) { + if(isOnlyTreasure(card, context.getPlayer()) || card instanceof VictoryCard || currentCount == 0 || rand.nextInt(MAX_OF_ONE_ACTION_CARD) < currentCount) { randList.add(card); } } From c0b423b33ad6aab4128cef7dc9bacde03b974278 Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 25 Jan 2016 23:10:54 -0700 Subject: [PATCH 063/141] Inheritance: Removing uneeded references to ActionCard class. --- vdom/src/com/vdom/core/ActionCardImpl.java | 8 +- vdom/src/com/vdom/core/BasePlayer.java | 74 ++++++++--------- .../com/vdom/core/CallableActionCardImpl.java | 8 +- vdom/src/com/vdom/core/CallableCard.java | 3 +- .../vdom/core/CallableTreasureCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 2 +- vdom/src/com/vdom/core/EventCardImpl.java | 37 +++++---- vdom/src/com/vdom/core/Game.java | 14 ++-- vdom/src/com/vdom/core/IndirectPlayer.java | 83 +++++++++---------- vdom/src/com/vdom/core/Player.java | 61 +++++++------- vdom/src/com/vdom/core/QuickPlayPlayer.java | 8 +- vdom/src/com/vdom/core/RemotePlayer.java | 15 +--- .../src/com/vdom/players/VDomPlayerChuck.java | 5 +- vdom/src/com/vdom/players/VDomPlayerEarl.java | 15 ++-- .../com/vdom/players/VDomPlayerPatrick.java | 59 +++++++------ .../src/com/vdom/players/VDomPlayerSarah.java | 10 +-- 16 files changed, 194 insertions(+), 210 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 0d182d04d..25cce4ba1 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -1326,7 +1326,7 @@ private void mine(MoveContext context, Player currentPlayer) { } private void university(MoveContext context, Player currentPlayer) { - ActionCard cardToObtain = currentPlayer.controlPlayer.university_actionCardToObtain(context); + Card cardToObtain = currentPlayer.controlPlayer.university_actionCardToObtain(context); if (cardToObtain != null && cardToObtain.isAction(null) && cardToObtain.getCost(context) <= 5 && !cardToObtain.costPotion()) { currentPlayer.gainNewCard(cardToObtain, this.controlCard, context); } @@ -3793,7 +3793,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { if (toOrder.size() == 1) { toPlay = toOrder.toArray(new Card[toOrder.size()]); } else { - ActionCard[] playOrder = currentPlayer.controlPlayer.golem_cardOrder(context, toOrder.toArray(new ActionCard[toOrder.size()])); + Card[] playOrder = currentPlayer.controlPlayer.golem_cardOrder(context, toOrder.toArray(new Card[toOrder.size()])); if (playOrder == null) { Util.playerError(currentPlayer, "Nothing back from golem_cardOrder, using order found"); @@ -3861,7 +3861,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { boolean shouldKeep = true; if (draw.isAction(currentPlayer)) { - shouldKeep = currentPlayer.controlPlayer.library_shouldKeepAction(context, (ActionCard) draw); + shouldKeep = currentPlayer.controlPlayer.library_shouldKeepAction(context, draw); } if (shouldKeep) { @@ -5537,7 +5537,7 @@ private void bandOfMisfits(Game game, MoveContext context, Player currentPlayer) // Already impersonating another card? if (!this.isImpersonatingAnotherCard()) { // Get card to impersonate - ActionCard cardToImpersonate = currentPlayer.controlPlayer.bandOfMisfits_actionCardToImpersonate(context); + Card cardToImpersonate = currentPlayer.controlPlayer.bandOfMisfits_actionCardToImpersonate(context); if (cardToImpersonate != null && !game.isPileEmpty(cardToImpersonate) && Cards.isSupplyCard(cardToImpersonate) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index cac3386a3..0ba797440 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Random; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CardCostComparator; import com.vdom.api.CardValueComparator; @@ -691,7 +690,7 @@ else if (shouldDiscard(card, context.player)) { } @Override - public boolean library_shouldKeepAction(MoveContext context, ActionCard action) { + public boolean library_shouldKeepAction(MoveContext context, Card action) { if (context.getActionsLeft() == 0) { return false; } @@ -1154,7 +1153,7 @@ public Card[] prince_cardCandidates(MoveContext context, ArrayList cardLis if (card.isAction(context.player) && card.getCost(context) <= 4 && !card.costPotion()) { if ( !card.isRuins(context.player) && !card.equals(Cards.necropolis) - && !((ActionCard) card).trashForced() + && !card.trashForced() && !(card.isDuration(context.player)) && !(card.isReserve(context.player)) && !(card.isTraveller(context.player)) @@ -1335,9 +1334,9 @@ public boolean explorer_shouldRevealProvince(MoveContext context) { } @Override - public ActionCard university_actionCardToObtain(MoveContext context) { + public Card university_actionCardToObtain(MoveContext context) { //TODO: better logic - return (ActionCard) bestCardInPlay(context, 5, false, false, true, false, false); + return bestCardInPlay(context, 5, false, false, true, false, false); } @Override @@ -1518,11 +1517,11 @@ public Card contraband_cardPlayerCantBuy(MoveContext context) { } @Override - public ActionCard kingsCourt_cardToPlay(MoveContext context) { + public Card kingsCourt_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { if(c.isAction(context.getPlayer())) { - return (ActionCard) c; + return c; } } @@ -1530,7 +1529,7 @@ public ActionCard kingsCourt_cardToPlay(MoveContext context) { } @Override - public ActionCard throneRoom_cardToPlay(MoveContext context) { + public Card throneRoom_cardToPlay(MoveContext context) { return controlPlayer.kingsCourt_cardToPlay(context); } @@ -1641,7 +1640,7 @@ public ArrayList treasureCardsToPlayInOrder(MoveContext context, i } @Override - public ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards) { + public Card[] golem_cardOrder(MoveContext context, Card[] cards) { return cards; } @@ -2059,7 +2058,7 @@ public boolean tunnel_shouldReveal(MoveContext context) { } @Override - public ActionCard scheme_actionToPutOnTopOfDeck(MoveContext context, ActionCard[] actions) { + public Card scheme_actionToPutOnTopOfDeck(MoveContext context, Card[] actions) { /* don't put prince cards back on top */ if(actions == null || actions.length == 0) { return null; @@ -2190,7 +2189,7 @@ public Card[] inn_cardsToDiscard(MoveContext context) { } @Override - public boolean inn_shuffleCardBackIntoDeck(MoveContext context, ActionCard card) { + public boolean inn_shuffleCardBackIntoDeck(MoveContext context, Card card) { return true; } @@ -2528,8 +2527,8 @@ public Card[] storeroom_cardsToDiscardForCoins(MoveContext context) { } @Override - public ActionCard procession_cardToPlay(MoveContext context) { - return controlPlayer.kingsCourt_cardToPlay(context); + public Card procession_cardToPlay(MoveContext context) { + return controlPlayer.kingsCourt_cardToPlay(context); } @Override @@ -2906,11 +2905,11 @@ public Card dameNatalie_cardToObtain(MoveContext context) { } @Override - public ActionCard bandOfMisfits_actionCardToImpersonate(MoveContext context) { + public Card bandOfMisfits_actionCardToImpersonate(MoveContext context) { if (context.getPlayer().getHand().contains(Cards.treasureMap)) { - return (ActionCard) Cards.treasureMap; + return Cards.treasureMap; } - return (ActionCardImpl) bestCardInPlay(context, 4, false, false, true, true, true); + return bestCardInPlay(context, 4, false, false, true, true, true); } @Override @@ -3250,7 +3249,7 @@ public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard return null; } - public CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards) { + public CallableCard call_whenActionResolveCardToCall(MoveContext context, Card resolvedAction, CallableCard[] possibleCards) { // Check coin of the Realm first boolean hasMoreActionsLeft = false; for (Card c : getHand()) { @@ -3356,11 +3355,11 @@ private Card getBestActionCard(CardList hand, MoveContext context) { } @Override - public ActionCard disciple_cardToPlay(MoveContext context) { + public Card disciple_cardToPlay(MoveContext context) { //TODO better logic for (Card c : context.getPlayer().getHand()) { if(c.isAction(context.getPlayer())) { - return (ActionCard) c; + return c; } } return null; @@ -3528,7 +3527,7 @@ private List getUnplacedTokens(MoveContext context) { } @Override - public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token) { + public Card teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token) { // TODO: better logic based on token type and how many cards we have or want to have of the augmented card Card[] cards = context.game.getCardsInGame(); Arrays.sort(cards, new Util.CardCostComparatorDesc()); @@ -3536,7 +3535,7 @@ public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerS if (c.isAction(null) && Cards.isSupplyCard(c) && game.getPlayerSupplyTokens(c, this).size() == 0) - return (ActionCard) c; + return c; } return null; } @@ -3620,19 +3619,19 @@ public Card[] bonfire_cardsToTrash(MoveContext context) { } @Override - public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { - return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + public Card ferry_actionCardPileToHaveToken(MoveContext context) { + return bestCardInPlay(context, COST_MAX, false, true, true, true, true); } @Override - public ActionCard inheritance_actionCardTosetAside(MoveContext context) { + public Card inheritance_actionCardTosetAside(MoveContext context) { //TODO: favor cantrips - return (ActionCard) bestCardInPlay(context, 4, false, false, true, false, true); + return bestCardInPlay(context, 4, false, false, true, false, true); } @Override - public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { - return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + public Card lostArts_actionCardPileToHaveToken(MoveContext context) { + return bestCardInPlay(context, COST_MAX, false, true, true, true, true); } public ExtraTurnOption extraTurn_chooseOption(MoveContext context, ExtraTurnOption[] options) { @@ -3645,8 +3644,8 @@ public ExtraTurnOption extraTurn_chooseOption(MoveContext context, ExtraTurnOpti } @Override - public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { - return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + public Card pathfinding_actionCardPileToHaveToken(MoveContext context) { + return bestCardInPlay(context, COST_MAX, false, true, true, true, true); } @Override @@ -3678,8 +3677,9 @@ public Card[] pilgrimage_cardsToGain(MoveContext context) { } @Override - public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { - return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + public Card plan_actionCardPileToHaveToken(MoveContext context) { + //TODO: favor lower cards we'd want a lot of (e.g. villages, cantrips) + return bestCardInPlay(context, COST_MAX, false, true, true, true, true); } @Override @@ -3739,13 +3739,13 @@ public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { } @Override - public ActionCard seaway_cardToObtain(MoveContext context) { - return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); + public Card seaway_cardToObtain(MoveContext context) { + return bestCardInPlay(context, 4, false, false, true, true, true); } @Override - public ActionCard summon_cardToObtain(MoveContext context) { - return (ActionCard) bestCardInPlay(context, 4, false, false, true, true, true); + public Card summon_cardToObtain(MoveContext context) { + return bestCardInPlay(context, 4, false, false, true, true, true); } public Card[] trade_cardsToTrash(MoveContext context) { @@ -3753,8 +3753,8 @@ public Card[] trade_cardsToTrash(MoveContext context) { } @Override - public ActionCard training_actionCardPileToHaveToken(MoveContext context) { - return (ActionCard) bestCardInPlay(context, COST_MAX, false, true, true, true, true); + public Card training_actionCardPileToHaveToken(MoveContext context) { + return bestCardInPlay(context, COST_MAX, false, true, true, true, true); } @Override diff --git a/vdom/src/com/vdom/core/CallableActionCardImpl.java b/vdom/src/com/vdom/core/CallableActionCardImpl.java index 29c083a42..6fd1099e9 100644 --- a/vdom/src/com/vdom/core/CallableActionCardImpl.java +++ b/vdom/src/com/vdom/core/CallableActionCardImpl.java @@ -134,7 +134,7 @@ public void callWhenCardGained(MoveContext context, Card cardToGain) { finishCall(context); } - public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction) { + public void callWhenActionResolved(MoveContext context, Card resolvedAction) { if (!callableWhenActionResolved) return; if (!call(context)) return; Game game = context.game; @@ -239,13 +239,13 @@ private void royalCarriage(Card resolvedAction, MoveContext context, Game game, private void teacher(MoveContext context, Game game, Player currentPlayer) { //look to see if we have a free pile int numFreePiles = 0; - ActionCard lastFreePile = null; + Card lastFreePile = null; for (Card c : game.getCardsInGame()) { if (game.getPile(c).isSupply() && c.isAction(null) && game.getPlayerSupplyTokens(c, currentPlayer).size() == 0) { numFreePiles++; - lastFreePile = (ActionCard) c; + lastFreePile = c; } } if (numFreePiles == 0) @@ -261,7 +261,7 @@ private void teacher(MoveContext context, Game game, Player currentPlayer) { token = PlayerSupplyToken.PlusOneBuy; } - ActionCard card; + Card card; if (numFreePiles == 1) { card = lastFreePile; } else { diff --git a/vdom/src/com/vdom/core/CallableCard.java b/vdom/src/com/vdom/core/CallableCard.java index 8e1faa2b4..f2a55032d 100644 --- a/vdom/src/com/vdom/core/CallableCard.java +++ b/vdom/src/com/vdom/core/CallableCard.java @@ -1,6 +1,5 @@ package com.vdom.core; -import com.vdom.api.ActionCard; import com.vdom.api.Card; public interface CallableCard extends Card { @@ -16,7 +15,7 @@ public interface CallableCard extends Card { public void callWhenCardGained(MoveContext context, Card cardToGain); - public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction); + public void callWhenActionResolved(MoveContext context, Card resolvedAction); public void callAtStartOfTurn(MoveContext context); } diff --git a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java index 73dbf5764..3e645fb3d 100644 --- a/vdom/src/com/vdom/core/CallableTreasureCardImpl.java +++ b/vdom/src/com/vdom/core/CallableTreasureCardImpl.java @@ -130,7 +130,7 @@ public void callWhenCardGained(MoveContext context, Card cardToGain) { finishCall(context); } - public void callWhenActionResolved(MoveContext context, ActionCard resolvedAction) { + public void callWhenActionResolved(MoveContext context, Card resolvedAction) { if (!callableWhenActionResolved) return; if (!call(context)) return; Game game = context.game; diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 391eccbe0..8b8529243 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -484,7 +484,7 @@ void setControlCard(CardImpl controlCard) { this.controlCard = controlCard; } - protected void placeToken(MoveContext context, ActionCard card, PlayerSupplyToken token) { + protected void placeToken(MoveContext context, Card card, PlayerSupplyToken token) { if (card == null) { Card[] cards = context.game.getActionsInGame(); if (cards.length != 0) { diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index bfcdb125a..3f27c40fb 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -203,13 +203,14 @@ protected void borrow(MoveContext context) { } private void ferry(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.ferry_actionCardPileToHaveToken(context); - placeToken(context, card, PlayerSupplyToken.MinusTwoCost); + Card card = context.getPlayer().controlPlayer.ferry_actionCardPileToHaveToken(context); + if (card.isAction(null)) + placeToken(context, card, PlayerSupplyToken.MinusTwoCost); } private void inheritance(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.inheritance_actionCardTosetAside(context); - if (card != null) { + Card card = context.getPlayer().controlPlayer.inheritance_actionCardTosetAside(context); + if (card != null && card.isAction(null)) { if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card) && !card.isVictory(context)) { context.player.inheritance = context.game.takeFromPile(card, context); GameEvent event = new GameEvent(GameEvent.Type.CardSetAsideInheritance, context); @@ -220,8 +221,9 @@ private void inheritance(MoveContext context) { } private void lostArts(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.lostArts_actionCardPileToHaveToken(context); - placeToken(context, card, PlayerSupplyToken.PlusOneAction); + Card card = context.getPlayer().controlPlayer.lostArts_actionCardPileToHaveToken(context); + if (card.isAction(null)) + placeToken(context, card, PlayerSupplyToken.PlusOneAction); } private void mission(MoveContext context) { @@ -230,8 +232,9 @@ private void mission(MoveContext context) { } private void pathfinding(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.pathfinding_actionCardPileToHaveToken(context); - placeToken(context, card, PlayerSupplyToken.PlusOneCard); + Card card = context.getPlayer().controlPlayer.pathfinding_actionCardPileToHaveToken(context); + if (card.isAction(null)) + placeToken(context, card, PlayerSupplyToken.PlusOneCard); } private void pilgrimage(MoveContext context) { @@ -260,8 +263,9 @@ private void pilgrimage(MoveContext context) { } private void plan(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.plan_actionCardPileToHaveToken(context); - placeToken(context, card, PlayerSupplyToken.Trashing); + Card card = context.getPlayer().controlPlayer.plan_actionCardPileToHaveToken(context); + if (card.isAction(null)) + placeToken(context, card, PlayerSupplyToken.Trashing); } private void quest(MoveContext context) { @@ -441,8 +445,8 @@ private void scoutingParty(MoveContext context) { } private void seaway(MoveContext context) { - ActionCard card = context.player.controlPlayer.seaway_cardToObtain(context); - if (card != null) { + Card card = context.player.controlPlayer.seaway_cardToObtain(context); + if (card != null && card.isAction(null)) { if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card)) { Card gainedCard = context.player.gainNewCard(card, this.controlCard, context); if (card.equals(gainedCard)) @@ -453,8 +457,8 @@ private void seaway(MoveContext context) { } private void summon(MoveContext context) { - ActionCard card = context.player.controlPlayer.summon_cardToObtain(context); - if (card != null) { + Card card = context.player.controlPlayer.summon_cardToObtain(context); + if (card != null && card.isAction(null)) { if (card.getCost(context) <= 4 && !context.game.isPileEmpty(card)) { context.player.gainNewCard(card, this.controlCard, context); } @@ -462,8 +466,9 @@ private void summon(MoveContext context) { } private void training(MoveContext context) { - ActionCard card = context.getPlayer().controlPlayer.training_actionCardPileToHaveToken(context); - placeToken(context, card, PlayerSupplyToken.PlusOneCoin); + Card card = context.getPlayer().controlPlayer.training_actionCardPileToHaveToken(context); + if (card.isAction(null)) + placeToken(context, card, PlayerSupplyToken.PlusOneCoin); } private void trade(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 8bd85e614..8ed56aa36 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -669,19 +669,19 @@ protected void playerAction(Player player, MoveContext context) { Card action = null; do { action = null; - ArrayList actionCards = null; + ArrayList actionCards = null; if (!actionChains || player.controlPlayer.isAi()) { - action = (ActionCard) player.controlPlayer.doAction(context); + action = player.controlPlayer.doAction(context); if (action != null) { - actionCards = new ArrayList(); - actionCards.add((ActionCard) action); + actionCards = new ArrayList(); + actionCards.add(action); } } else { Card[] cs = player.controlPlayer.actionCardsToPlayInOrder(context); if (cs != null && cs.length != 0) { - actionCards = new ArrayList(); + actionCards = new ArrayList(); for (int i = 0; i < cs.length; i++) { - actionCards.add((ActionCard) cs[i]); + actionCards.add(cs[i]); } } } @@ -2709,7 +2709,7 @@ public void gameEvent(GameEvent event) { Card c = player.discard.get(i); if(c.isAction(player)) { actionCardsFound++; - if(player.controlPlayer.inn_shuffleCardBackIntoDeck(event.getContext(), (ActionCard) c)) { + if(player.controlPlayer.inn_shuffleCardBackIntoDeck(event.getContext(), c)) { cards.add(c); } } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 05ad94173..f1fe04121 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -6,15 +6,12 @@ import java.util.List; import java.util.Set; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; -import com.vdom.comms.Event; import com.vdom.comms.SelectCardOptions; -import com.vdom.comms.Event.EType; -import com.vdom.comms.SelectCardOptions.PickType; import com.vdom.comms.SelectCardOptions.ActionType; +import com.vdom.comms.SelectCardOptions.PickType; /** * Class that you can use to play remotely. @@ -417,7 +414,7 @@ public Card[] cellar_cardsToDiscard(MoveContext context) { } @Override - public boolean library_shouldKeepAction(MoveContext context, ActionCard action) { + public boolean library_shouldKeepAction(MoveContext context, Card action) { if(context.isQuickPlay() && shouldAutoPlay_library_shouldKeepAction(context, action)) { return super.library_shouldKeepAction(context, action); } @@ -994,13 +991,13 @@ public Card apprentice_cardToTrash(MoveContext context) { } @Override - public ActionCard university_actionCardToObtain(MoveContext context) { + public Card university_actionCardToObtain(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_university_actionCardToObtain(context)) { return super.university_actionCardToObtain(context); } SelectCardOptions sco = new SelectCardOptions().potionCost(0).maxCost(5).isAction() .setPassable().setCardResponsible(Cards.university); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -1016,7 +1013,7 @@ public boolean scryingPool_shouldDiscard(MoveContext context, Player targetPlaye } @Override - public ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards) { + public Card[] golem_cardOrder(MoveContext context, Card[] cards) { if(context.isQuickPlay() && shouldAutoPlay_golem_cardOrder(context, cards)) { return super.golem_cardOrder(context, cards); } @@ -1029,7 +1026,7 @@ public ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards) { if (o == 0) { return cards; } - return new ActionCard[]{ cards[1], cards[0] }; + return new Card[]{ cards[1], cards[0] }; } @Override @@ -1123,25 +1120,25 @@ public Card[] goons_attack_cardsToKeep(MoveContext context) { } @Override - public ActionCard kingsCourt_cardToPlay(MoveContext context) { + public Card kingsCourt_cardToPlay(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_kingsCourt_cardToPlay(context)) { return super.kingsCourt_cardToPlay(context); } SelectCardOptions sco = new SelectCardOptions().isAction() .setPassable().setPickType(PickType.PLAY) .setCardResponsible(Cards.kingsCourt); - return (ActionCard) getCardFromHand(context, sco); + return getCardFromHand(context, sco); } @Override - public ActionCard throneRoom_cardToPlay(MoveContext context) { + public Card throneRoom_cardToPlay(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_throneRoom_cardToPlay(context)) { return super.throneRoom_cardToPlay(context); } SelectCardOptions sco = new SelectCardOptions().isAction() .setPickType(PickType.PLAY) .setCardResponsible(Cards.throneRoom); - return (ActionCard) getCardFromHand(context, sco); + return getCardFromHand(context, sco); } @Override @@ -1649,12 +1646,12 @@ public Card[] cartographer_cardOrder(MoveContext context, Card[] cards) { } @Override - public ActionCard scheme_actionToPutOnTopOfDeck(MoveContext context, ActionCard[] actions) { + public Card scheme_actionToPutOnTopOfDeck(MoveContext context, Card[] actions) { if(context.isQuickPlay() && shouldAutoPlay_scheme_actionToPutOnTopOfDeck(context, actions)) { return super.scheme_actionToPutOnTopOfDeck(context, actions); } - ArrayList options = new ArrayList(); - for (ActionCard c : actions) + ArrayList options = new ArrayList(); + for (Card c : actions) options.add(c); options.add(null); return options.get(selectOption(context, Cards.scheme, options.toArray())); @@ -1716,7 +1713,7 @@ public Card[] inn_cardsToDiscard(MoveContext context) { } @Override - public boolean inn_shuffleCardBackIntoDeck(MoveContext context, ActionCard card) { + public boolean inn_shuffleCardBackIntoDeck(MoveContext context, Card card) { if(context.isQuickPlay() && shouldAutoPlay_inn_shuffleCardBackIntoDeck(context, card)) { return super.inn_shuffleCardBackIntoDeck(context, card); } @@ -2119,14 +2116,13 @@ public Card[] storeroom_cardsToDiscardForCoins(MoveContext context) { } @Override - public ActionCard procession_cardToPlay(MoveContext context) { + public Card procession_cardToPlay(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_throneRoom_cardToPlay(context)) { return super.procession_cardToPlay(context); } SelectCardOptions sco = new SelectCardOptions().isAction() - .setPassable().setPickType(PickType.PLAY) .setCardResponsible(Cards.procession); - return (ActionCard) getCardFromHand(context, sco); + return getCardFromHand(context, sco); } @Override @@ -2434,14 +2430,14 @@ public Card dameNatalie_cardToObtain(MoveContext context) { } @Override - public ActionCard bandOfMisfits_actionCardToImpersonate(MoveContext context) { + public Card bandOfMisfits_actionCardToImpersonate(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_bandOfMisfits_actionCardToImpersonate(context)) { return super.bandOfMisfits_actionCardToImpersonate(context); } SelectCardOptions sco = new SelectCardOptions().potionCost(0) .maxCost(Cards.bandOfMisfits.getCost(context) - 1).isAction() .setCardResponsible(Cards.bandOfMisfits); - return (ActionCardImpl) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -2676,7 +2672,7 @@ public CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard } @Override - public CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards) { + public CallableCard call_whenActionResolveCardToCall(MoveContext context, Card resolvedAction, CallableCard[] possibleCards) { if(context.isQuickPlay() && shouldAutoPlay_call_whenActionResolveCardToCall(context, resolvedAction, possibleCards)) { return super.call_whenActionResolveCardToCall(context, resolvedAction, possibleCards); } @@ -2704,14 +2700,14 @@ public CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCa } @Override - public ActionCard disciple_cardToPlay(MoveContext context) { + public Card disciple_cardToPlay(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_disciple_cardToPlay(context)) { return super.disciple_cardToPlay(context); } SelectCardOptions sco = new SelectCardOptions().isAction() .setPassable().setPickType(PickType.PLAY) .setCardResponsible(Cards.disciple); - return (ActionCard) getCardFromHand(context, sco); + return getCardFromHand(context, sco); } @Override @@ -2835,15 +2831,14 @@ public PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context) { } @Override - public ActionCard teacher_actionCardPileToHaveToken(MoveContext context, + public Card teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token) { if(context.isQuickPlay() && shouldAutoPlay_teacher_actionCardPileToHaveToken(context, token)) { return super.teacher_actionCardPileToHaveToken(context, token); } SelectCardOptions sco = new SelectCardOptions() .isAction().noTokens().setCardResponsible(Cards.teacher); - //TODO: specify can only select piles without a token - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -2920,44 +2915,44 @@ public Card[] bonfire_cardsToTrash(MoveContext context) { } @Override - public ActionCard ferry_actionCardPileToHaveToken(MoveContext context) { + public Card ferry_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_ferry_actionCardPileToHaveToken(context)) { return super.ferry_actionCardPileToHaveToken(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().setCardResponsible(Cards.ferry); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override - public ActionCard inheritance_actionCardTosetAside(MoveContext context) { + public Card inheritance_actionCardTosetAside(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_inheritance_actionCardTosetAside(context)) { return super.inheritance_actionCardTosetAside(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().isNonVictory().maxCost(4).potionCost(0) .setActionType(ActionType.SETASIDE).setCardResponsible(Cards.inheritance); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override - public ActionCard lostArts_actionCardPileToHaveToken(MoveContext context) { + public Card lostArts_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_lostArts_actionCardPileToHaveToken(context)) { return super.lostArts_actionCardPileToHaveToken(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().setCardResponsible(Cards.lostArts); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override - public ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context) { + public Card pathfinding_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_pathfinding_actionCardPileToHaveToken(context)) { return super.pathfinding_actionCardPileToHaveToken(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().setCardResponsible(Cards.pathfinding); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -2972,13 +2967,13 @@ public Card[] pilgrimage_cardsToGain(MoveContext context) { } @Override - public ActionCard plan_actionCardPileToHaveToken(MoveContext context) { + public Card plan_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_plan_actionCardPileToHaveToken(context)) { return super.plan_actionCardPileToHaveToken(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().setCardResponsible(Cards.plan); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -3032,23 +3027,23 @@ public Card scoutingParty_cardToDiscard(MoveContext context, Card[] cards) { } @Override - public ActionCard seaway_cardToObtain(MoveContext context) { + public Card seaway_cardToObtain(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_seaway_cardToObtain(context)) { return super.seaway_cardToObtain(context); } SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) .setCardResponsible(Cards.seaway).isAction().setActionType(ActionType.GAIN); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override - public ActionCard summon_cardToObtain(MoveContext context) { + public Card summon_cardToObtain(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_summon_cardToObtain(context)) { return super.summon_cardToObtain(context); } SelectCardOptions sco = new SelectCardOptions().maxCost(4).potionCost(0) .setCardResponsible(Cards.summon).isAction().setActionType(ActionType.GAIN); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override @@ -3063,13 +3058,13 @@ public Card[] trade_cardsToTrash(MoveContext context) { } @Override - public ActionCard training_actionCardPileToHaveToken(MoveContext context) { + public Card training_actionCardPileToHaveToken(MoveContext context) { if(context.isQuickPlay() && shouldAutoPlay_training_actionCardPileToHaveToken(context)) { return super.training_actionCardPileToHaveToken(context); } SelectCardOptions sco = new SelectCardOptions() .isAction().setCardResponsible(Cards.training); - return (ActionCard) getFromTable(context, sco); + return getFromTable(context, sco); } @Override diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 38cf55774..87496d235 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -7,10 +7,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Random; +import java.util.Set; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CurseCard; import com.vdom.api.GameEvent; @@ -132,7 +131,7 @@ public int getMyAddActionCardCount() { int addActionsCards = 0; for (Card card : getAllCards()) { if (card.isAction(this)) { - if (((ActionCard) card).getAddActions() > 0) { + if (card.getAddActions() > 0) { addActionsCards++; } } @@ -145,7 +144,7 @@ public int getMyAddCardCardCount() { int addCards = 0; for (Card card : getAllCards()) { if (card.isAction(this)) { - if (((ActionCard) card).getAddCards() > 0) { + if (card.getAddCards() > 0) { addCards++; } } @@ -158,7 +157,7 @@ public int getMyAddActions() { int addActions = 0; for (Card card : getAllCards()) { if (card.isAction(this)) { - addActions += ((ActionCard) card).getAddActions(); + addActions += card.getAddActions(); } } @@ -169,7 +168,7 @@ public int getMyAddCards() { int addCards = 0; for (Card card : getAllCards()) { if (card.isAction(this)) { - addCards += ((ActionCard) card).getAddCards(); + addCards += card.getAddCards(); } } @@ -180,7 +179,7 @@ public int getMyAddBuys() { int addBuys = 0; for (Card card : getAllCards()) { if (card.isAction(this)) { - addBuys += ((ActionCard) card).getAddBuys(); + addBuys += card.getAddBuys(); } } @@ -404,7 +403,7 @@ protected void cleanup(MoveContext context) { break; } - ActionCard actionToPutBack = controlPlayer.scheme_actionToPutOnTopOfDeck(((MoveContext) context), actions.toArray(new ActionCard[0])); + Card actionToPutBack = controlPlayer.scheme_actionToPutOnTopOfDeck(((MoveContext) context), actions.toArray(new Card[0])); if(actionToPutBack == null) { break; } @@ -1400,12 +1399,12 @@ public ArrayList getVictoryInHand() { return victory; } - public ArrayList getActionsInHand(Player player) { - ArrayList actions = new ArrayList(); + public ArrayList getActionsInHand(Player player) { + ArrayList actions = new ArrayList(); for (Card c : getHand()) if (c.isAction(player)) - actions.add((ActionCard) c); + actions.add(c); return actions; } @@ -1448,7 +1447,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] cellar_cardsToDiscard(MoveContext context); - public abstract boolean library_shouldKeepAction(MoveContext context, ActionCard action); + public abstract boolean library_shouldKeepAction(MoveContext context, Card action); public abstract boolean spy_shouldDiscard(MoveContext context, Player targetPlayer, Card card); @@ -1566,11 +1565,11 @@ public ArrayList getActionsInHand(Player player) { public abstract Card apprentice_cardToTrash(MoveContext context); - public abstract ActionCard university_actionCardToObtain(MoveContext context); + public abstract Card university_actionCardToObtain(MoveContext context); public abstract boolean scryingPool_shouldDiscard(MoveContext context, Player targetPlayer, Card card); - public abstract ActionCard[] golem_cardOrder(MoveContext context, ActionCard[] cards); + public abstract Card[] golem_cardOrder(MoveContext context, Card[] cards); // //////////////////////////////////////////// // Card interactions - cards from Prosperity @@ -1593,9 +1592,9 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] goons_attack_cardsToKeep(MoveContext context); - public abstract ActionCard kingsCourt_cardToPlay(MoveContext context); + public abstract Card kingsCourt_cardToPlay(MoveContext context); - public abstract ActionCard throneRoom_cardToPlay(MoveContext context); + public abstract Card throneRoom_cardToPlay(MoveContext context); public abstract boolean loan_shouldTrashTreasure(MoveContext context, TreasureCard treasure); @@ -1689,7 +1688,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] cartographer_cardOrder(MoveContext context, Card[] cards); - public abstract ActionCard scheme_actionToPutOnTopOfDeck(MoveContext context, ActionCard[] actions); + public abstract Card scheme_actionToPutOnTopOfDeck(MoveContext context, Card[] actions); public abstract boolean tunnel_shouldReveal(MoveContext context); @@ -1707,7 +1706,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] inn_cardsToDiscard(MoveContext context); - public abstract boolean inn_shuffleCardBackIntoDeck(MoveContext context, ActionCard card); + public abstract boolean inn_shuffleCardBackIntoDeck(MoveContext context, Card card); public abstract Card mandarin_cardToReplace(MoveContext context); @@ -1772,7 +1771,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] storeroom_cardsToDiscardForCoins(MoveContext context); - public abstract ActionCard procession_cardToPlay(MoveContext context); + public abstract Card procession_cardToPlay(MoveContext context); public abstract Card procession_cardToGain(MoveContext context, int maxCost, boolean potion); @@ -1804,7 +1803,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card hermit_cardToTrash(MoveContext context, ArrayList cardList, int nonTreasureCountInDiscard); public abstract Card hermit_cardToGain(MoveContext context); - public abstract ActionCard bandOfMisfits_actionCardToImpersonate(MoveContext context); + public abstract Card bandOfMisfits_actionCardToImpersonate(MoveContext context); // //////////////////////////////////////////// // Card interactions - Guilds Expansion @@ -1836,9 +1835,9 @@ public ArrayList getActionsInHand(Player player) { public abstract Card[] artificer_cardsToDiscard(MoveContext context); public abstract Card artificer_cardToObtain(MoveContext context, int cost); public abstract CallableCard call_whenGainCardToCall(MoveContext context, Card gainedCard, CallableCard[] possibleCards); - public abstract CallableCard call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedAction, CallableCard[] possibleCards); + public abstract CallableCard call_whenActionResolveCardToCall(MoveContext context, Card resolvedAction, CallableCard[] possibleCards); public abstract CallableCard call_whenTurnStartCardToCall(MoveContext context, CallableCard[] possibleCards); - public abstract ActionCard disciple_cardToPlay(MoveContext context); + public abstract Card disciple_cardToPlay(MoveContext context); public abstract Card fugitive_cardToDiscard(MoveContext context); public abstract Card[] gear_cardsToSetAside(MoveContext context); public abstract TreasureCard hero_treasureToObtain(MoveContext context); @@ -1852,7 +1851,7 @@ public ArrayList getActionsInHand(Player player) { public abstract Card raze_cardToKeep(MoveContext context, Card[] cards); public abstract Card soldier_cardToDiscard(MoveContext context); public abstract PlayerSupplyToken teacher_tokenTypeToMove(MoveContext context); - public abstract ActionCard teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token); + public abstract Card teacher_actionCardPileToHaveToken(MoveContext context, PlayerSupplyToken token); public abstract Card transmogrify_cardToTrash(MoveContext context); public abstract Card transmogrify_cardToObtain(MoveContext context, int maxCost, boolean potion); public abstract int cleanup_wineMerchantToDiscard(MoveContext context, int wineMerchantTotal); @@ -1864,20 +1863,20 @@ public ArrayList getActionsInHand(Player player) { public abstract Card alms_cardToObtain(MoveContext context); public abstract Card ball_cardToObtain(MoveContext context); public abstract Card[] bonfire_cardsToTrash(MoveContext context); - public abstract ActionCard ferry_actionCardPileToHaveToken(MoveContext context); - public abstract ActionCard inheritance_actionCardTosetAside(MoveContext context); - public abstract ActionCard lostArts_actionCardPileToHaveToken(MoveContext context); - public abstract ActionCard pathfinding_actionCardPileToHaveToken(MoveContext context); + public abstract Card ferry_actionCardPileToHaveToken(MoveContext context); + public abstract Card inheritance_actionCardTosetAside(MoveContext context); + public abstract Card lostArts_actionCardPileToHaveToken(MoveContext context); + public abstract Card pathfinding_actionCardPileToHaveToken(MoveContext context); public abstract Card[] pilgrimage_cardsToGain(MoveContext context); - public abstract ActionCard plan_actionCardPileToHaveToken(MoveContext context); + public abstract Card plan_actionCardPileToHaveToken(MoveContext context); public abstract QuestOption quest_chooseOption(MoveContext context); public abstract Card quest_attackCardToDiscard(MoveContext context, Card[] attacks); public abstract Card[] quest_cardsToDiscard(MoveContext context); public abstract Card save_cardToSetAside(MoveContext context); public abstract Card scoutingParty_cardToDiscard(MoveContext context, Card[] revealedCards); - public abstract ActionCard seaway_cardToObtain(MoveContext context); - public abstract ActionCard summon_cardToObtain(MoveContext context); - public abstract ActionCard training_actionCardPileToHaveToken(MoveContext context); + public abstract Card seaway_cardToObtain(MoveContext context); + public abstract Card summon_cardToObtain(MoveContext context); + public abstract Card training_actionCardPileToHaveToken(MoveContext context); public abstract Card trashingToken_cardToTrash(MoveContext context); public abstract Card[] trade_cardsToTrash(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 37c8d17d8..971773a07 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -103,7 +103,7 @@ public boolean shouldAutoPlay_cellar_cardsToDiscard(MoveContext context) { } - public boolean shouldAutoPlay_library_shouldKeepAction(MoveContext context, ActionCard action) { + public boolean shouldAutoPlay_library_shouldKeepAction(MoveContext context, Card action) { if(context.getActionsLeft() == 0) { return true; } @@ -724,7 +724,7 @@ public boolean shouldAutoPlay_haggler_cardToObtain(MoveContext context, int maxC return false; } - public boolean shouldAutoPlay_scheme_actionToPutOnTopOfDeck(MoveContext context, ActionCard[] actions) { + public boolean shouldAutoPlay_scheme_actionToPutOnTopOfDeck(MoveContext context, Card[] actions) { return false; } @@ -732,7 +732,7 @@ public boolean shouldAutoPlay_inn_cardsToDiscard(MoveContext context) { return true; } - public boolean shouldAutoPlay_inn_shuffleCardBackIntoDeck(MoveContext context, ActionCard card) { + public boolean shouldAutoPlay_inn_shuffleCardBackIntoDeck(MoveContext context, Card card) { return true; } @@ -829,7 +829,7 @@ public boolean shouldAutoPlay_call_whenGainCardToCall(MoveContext context, Card return false; } - public boolean shouldAutoPlay_call_whenActionResolveCardToCall(MoveContext context, ActionCard resolvedCard, CallableCard[] possibleCards) { + public boolean shouldAutoPlay_call_whenActionResolveCardToCall(MoveContext context, Card resolvedCard, CallableCard[] possibleCards) { return false; } diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 36fe9de33..3357cc7c8 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -6,10 +6,8 @@ import java.util.List; import java.util.Map; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CurseCard; -import com.vdom.api.DurationCard; import com.vdom.api.EventCard; import com.vdom.api.GameEvent; import com.vdom.api.GameEvent.Type; @@ -25,14 +23,6 @@ import com.vdom.comms.MyCard; import com.vdom.comms.NewGame; import com.vdom.comms.SelectCardOptions; -import com.vdom.core.CardList; -import com.vdom.core.Cards; -import com.vdom.core.ExitException; -import com.vdom.core.Game; -import com.vdom.core.IndirectPlayer; -import com.vdom.core.MoveContext; -import com.vdom.core.Player; -import com.vdom.core.Util; /** * Class that you can use to play remotely. @@ -194,10 +184,9 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla card.isTreasure = true; card.gold = tc.getValue(); } - if (c instanceof ActionCard) { - ActionCard ac = (ActionCard) c; + if (c.isAction(null)) { card.isAction = true; - if (c instanceof DurationCard) { + if (c.isDuration(null)) { card.isDuration = true; } } diff --git a/vdom/src/com/vdom/players/VDomPlayerChuck.java b/vdom/src/com/vdom/players/VDomPlayerChuck.java index d561a4b98..1956e7ee5 100644 --- a/vdom/src/com/vdom/players/VDomPlayerChuck.java +++ b/vdom/src/com/vdom/players/VDomPlayerChuck.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Random; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.TreasureCard; import com.vdom.core.BasePlayer; @@ -64,10 +63,10 @@ public Card doAction(MoveContext context) { princeCards = new Card[0]; } - ActionCard action; + Card action; for (final Card card : getHand()) { if (context.canPlay(card)) { - action = (ActionCard) card; + action = card; if (action.getAddActions() > 0 && !isInCardArray(card, princeCards)) { return action; } diff --git a/vdom/src/com/vdom/players/VDomPlayerEarl.java b/vdom/src/com/vdom/players/VDomPlayerEarl.java index 5ba4e4f04..c5271f2a3 100644 --- a/vdom/src/com/vdom/players/VDomPlayerEarl.java +++ b/vdom/src/com/vdom/players/VDomPlayerEarl.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Random; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CurseCard; import com.vdom.api.GameEvent; @@ -325,7 +324,7 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe continue; } - ActionCard action = (ActionCard)card; + Card action = card; if (context.canPlay(action)) { return action; } @@ -334,13 +333,13 @@ private Card calculateAction(int myTurnCount, Card[] hand, int throneRoomsInEffe return null; } - private ActionCard getBestAddActionAction(Card[] hand, Player player) { - ActionCard bestAction = null; + private Card getBestAddActionAction(Card[] hand, Player player) { + Card bestAction = null; int bestAddActions = 0; for (Card card : hand) { if (card.isAction(player)) { - ActionCard action = (ActionCard)card; + Card action = card; if (action.getAddActions() > 0) { int addCards = action.getAddCards(); @@ -357,13 +356,13 @@ private ActionCard getBestAddActionAction(Card[] hand, Player player) { return bestAction; } - private ActionCard getBestAddActionCard(Card[] hand, Player player) { - ActionCard bestAction = null; + private Card getBestAddActionCard(Card[] hand, Player player) { + Card bestAction = null; int bestAddCards = 0; for (Card card : hand) { if (card.isAction(player)) { - ActionCard action = (ActionCard)card; + Card action = card; int thisAddCards = action.getAddCards(); if (thisAddCards > bestAddCards) { bestAction = action; diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index 6c0ef63be..e5bc7aaec 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -5,13 +5,12 @@ import java.util.HashMap; import java.util.Random; -import com.vdom.api.ActionCard; import com.vdom.api.Card; import com.vdom.api.CardCostComparator; +import com.vdom.api.CurseCard; import com.vdom.api.GameEvent; import com.vdom.api.TreasureCard; import com.vdom.api.VictoryCard; -import com.vdom.api.CurseCard; import com.vdom.core.AbstractCardPile; import com.vdom.core.BasePlayer; import com.vdom.core.Cards; @@ -403,9 +402,9 @@ public int size() { private boolean debug = Game.debug; private StrategyOption strategy = StrategyOption.Nothing; - private ActionCard strategyCard = null; - private ArrayList strategyPossibleCards = new ArrayList(); - private ActionCard strategyMultiCardTerminal = null; + private Card strategyCard = null; + private ArrayList strategyPossibleCards = new ArrayList(); + private Card strategyMultiCardTerminal = null; //private ComboCards combo; @@ -1222,7 +1221,7 @@ public TorturerOption torturer_attack_chooseOption(MoveContext context) { public boolean shouldBuyPotion() { boolean ret = false; - for (ActionCard c : this.strategyPossibleCards) { + for (Card c : this.strategyPossibleCards) { ret = ret | c.costPotion(); } return ret; @@ -1289,7 +1288,7 @@ private Card advisorGeneral(MoveContext context, int gold, boolean exact, boolea TreasureCard maxMPC_card = null; VictoryCard maxVP_card = null; - ActionCard action_card = null; + Card action_card = null; ArrayList special_cards = new ArrayList(); ArrayList deck = this.getAllCards(); ArrayList potentialBuys = new ArrayList(); @@ -1389,14 +1388,14 @@ private Card advisorGeneral(MoveContext context, int gold, boolean exact, boolea } } // treasure - if ((card.equals(Cards.golem)) && (this.getCardCount(ActionCard.class, deck) > 1) && (this.strategy != StrategyOption.NoAction)) { - this.log("action: Golem (have " + this.getCardCount(ActionCard.class, deck) + " actions)"); + if ((card.equals(Cards.golem)) && (this.getActionCardCount(deck, context.player) > 1) && (this.strategy != StrategyOption.NoAction)) { + this.log("action: Golem (have " + this.getActionCardCount(deck, context.player) + " actions)"); potentialBuys.add(Cards.golem); } // action cards if ((this.strategyPossibleCards.contains(card)) && ((game.pileSize(Cards.curse) > 3) || (!knownCursingCards.contains(card)))) { - ActionCard ac = (ActionCard) card; + Card ac = card; // we can buy another piece of "single" card only when the deck is big enough @@ -1470,7 +1469,7 @@ private Card advisorGeneral(MoveContext context, int gold, boolean exact, boolea int embargopiles = 0; while (potentialBuys.size() > 0) { - action_card = (ActionCard) Util.randomCard(potentialBuys); + action_card = Util.randomCard(potentialBuys); potentialBuys.remove(action_card); if (game.embargos.containsKey(action_card.getName())) { this.log("action " + action_card + " is embargoed, skipping"); @@ -1845,7 +1844,7 @@ public void newGame(MoveContext context) { strategy = StrategyOption.Nothing; strategyCard = null; strategyMultiCardTerminal = null; - strategyPossibleCards = new ArrayList(); + strategyPossibleCards = new ArrayList(); //opponentActionCards = new ArrayList(); //opponentVP = -1000; @@ -1854,7 +1853,7 @@ public void newGame(MoveContext context) { } private void advisorAction() { - ArrayList cards = new ArrayList(); + ArrayList cards = new ArrayList(); boolean shouldReCurse = false; this.strategyPossibleCards.clear(); @@ -1868,7 +1867,7 @@ private void advisorAction() { if ((knownActionCards.contains(pile.card())) && (pile.getCount() > 2)) { if ((knownCursingCards.contains(pile.card())) || (!shouldReCurse)) { if (!game.embargos.containsKey(pile.card().getName())) { - cards.add((ActionCard) pile.card()); + cards.add(pile.card()); } else { this.log("advisorAction: skipped " + pile.card() + " due to embargo"); } @@ -1885,7 +1884,7 @@ private void advisorAction() { cards.clear(); for (Card c : tier1) { if (game.pileSize(c) > 2) { - cards.add((ActionCard) c); + cards.add(c); } } } @@ -1914,12 +1913,12 @@ private void advisorAction() { for (AbstractCardPile pile : game.piles.values()) { if (VDomPlayerPatrick.knownMultiActionCards.contains(pile.card())) { - this.strategyPossibleCards.add((ActionCard) pile.card()); + this.strategyPossibleCards.add(pile.card()); } } for (AbstractCardPile pile : game.piles.values()) { if (VDomPlayerPatrick.knownComboActionCards.contains(pile.card())) { - this.strategyPossibleCards.add((ActionCard) pile.card()); + this.strategyPossibleCards.add(pile.card()); } } } else if (knownDoubleActionCards.contains(this.strategyCard)) { @@ -2015,7 +2014,7 @@ public void gameEvent(GameEvent event) { Card card = event.getCard(); if (card.isAction(event.player)) { - ActionCard ac = (ActionCard) card; + Card ac = card; this.opponents.get(event.player.playerNumber).putActionCard(card); if (ac.isAttack(event.player)) { this.opponents.get(event.player.playerNumber).setAttacking(true); @@ -2156,7 +2155,7 @@ private int needPotion() { // TODO must be tested return 0; } - for (ActionCard ac : this.strategyPossibleCards) { + for (Card ac : this.strategyPossibleCards) { if (ac.costPotion() && needpotion < 1) { needpotion = 1; } @@ -2324,7 +2323,7 @@ private ArrayList getStrategyCardsInDeck(MoveContext context, boolean only for (Card card : getAllCards()) { if (this.strategyPossibleCards.contains(card)) { - if (!isCantrip((ActionCard) card) || !onlyTerminals) { + if (!isCantrip(card) || !onlyTerminals) { ret.add(card); } } @@ -2338,7 +2337,7 @@ private ArrayList getTerminalsInDeck(MoveContext context) { for (Card card : getAllCards()) { if (card.isAction(context.player)) { - if (((ActionCard) card).getAddActions() <= 0) { + if (card.getAddActions() <= 0) { ret.add(card); } } @@ -2352,7 +2351,7 @@ private float getCardsPerHand(MoveContext context) { for (Card card : getAllCards()) { if (card.isAction(context.player)) { - addcards += ((ActionCard) card).getAddCards(); + addcards += card.getAddCards(); } } @@ -2372,10 +2371,10 @@ public Card haggler_cardToObtain(MoveContext context, int maxCost, boolean potio private Card advisorPlayAction(ArrayList hand, Player player) { this.log("advisorPlayAction: " + hand); - ArrayList ac = new ArrayList(); + ArrayList ac = new ArrayList(); for (Card card : hand) { if (card.isAction(player)) { - ac.add((ActionCard) card); + ac.add(card); } } ArrayList temphand = new ArrayList(hand); @@ -2403,7 +2402,7 @@ private Card advisorPlayAction(ArrayList hand, Player player) { } } - for (ActionCard a : ac) { + for (Card a : ac) { if (knownTrashingCards.contains(ac)) { if ((this.getDeckSize() < 6) || (getCardToTrash(DiscardOption.SemiDestructive) == null) || (a.equals(Cards.masquerade))) { ac.remove(a); @@ -2425,13 +2424,13 @@ private Card advisorPlayAction(ArrayList hand, Player player) { princeCards = new Card[0]; } - for (ActionCard a : ac) { + for (Card a : ac) { if (isCantrip(a) && !isInCardArray(a, princeCards)) { return a; } } - for (ActionCard a : ac) { + for (Card a : ac) { if (a.getAddActions() > 0 && !isInCardArray(a, princeCards)) { return a; } @@ -2442,10 +2441,10 @@ private Card advisorPlayAction(ArrayList hand, Player player) { return hand.get(hand.indexOf(Cards.prince)); } - ActionCard bestcoin = (ActionCard) Cards.village; - ActionCard bestcards = (ActionCard) Cards.militia; + Card bestcoin = Cards.village; + Card bestcards = Cards.militia; - for (ActionCard a : ac) { + for (Card a : ac) { if (a.equals(Cards.tactician) && playedCards.contains(Cards.tactician) ) { continue; } diff --git a/vdom/src/com/vdom/players/VDomPlayerSarah.java b/vdom/src/com/vdom/players/VDomPlayerSarah.java index 93d0a9108..7080f04f5 100644 --- a/vdom/src/com/vdom/players/VDomPlayerSarah.java +++ b/vdom/src/com/vdom/players/VDomPlayerSarah.java @@ -374,11 +374,11 @@ public String getPlayerName(boolean maskName) { @Override public Card doAction(MoveContext context) { - ArrayList actionCards = context.getPlayer().getActionsInHand(context.player); + ArrayList actionCards = context.getPlayer().getActionsInHand(context.player); // don't play rats if (game.isCardInGame(Cards.rats)) { - for (Iterator it = actionCards.iterator(); it.hasNext(); ) { + for (Iterator it = actionCards.iterator(); it.hasNext(); ) { if (Cards.rats.equals(it.next())) { it.remove(); } @@ -387,7 +387,7 @@ public Card doAction(MoveContext context) { // Pair of Treasure Maps goes first int treasureMapCount = 0; - for (Iterator it = actionCards.iterator(); it.hasNext(); ) { + for (Iterator it = actionCards.iterator(); it.hasNext(); ) { if (Cards.treasureMap.equals(it.next())) { treasureMapCount++; it.remove(); @@ -413,7 +413,7 @@ public Card doAction(MoveContext context) { // don't play trashForced cards if no trash cards available (Apprentice, Ambassador, etc) Card[] trashableCards = pickOutCards(context.getPlayer().getHand(), 1, getTrashCards()); if (trashableCards == null) { - for (Iterator it = actionCards.iterator(); it.hasNext(); ) { + for (Iterator it = actionCards.iterator(); it.hasNext(); ) { if (it.next().trashForced()) it.remove(); } @@ -422,7 +422,7 @@ public Card doAction(MoveContext context) { // play Action Cards that add more actions for (final Card card : actionCards) { if (context.canPlay(card)) { - ActionCard action = (ActionCard) card; + Card action = card; if (action.getAddActions() > 0 && !isInCardArray(card, princeCards)) return action; } From 8845a476eea975751cf6d0ad11e6c1dc9ca1681c Mon Sep 17 00:00:00 2001 From: dominionator Date: Mon, 25 Jan 2016 23:30:51 -0700 Subject: [PATCH 064/141] Inheritance: starting method for playing Victory card. --- vdom/src/com/vdom/core/VictoryCardImpl.java | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/vdom/src/com/vdom/core/VictoryCardImpl.java b/vdom/src/com/vdom/core/VictoryCardImpl.java index bb0767fb2..dc3e26e17 100644 --- a/vdom/src/com/vdom/core/VictoryCardImpl.java +++ b/vdom/src/com/vdom/core/VictoryCardImpl.java @@ -1,9 +1,6 @@ package com.vdom.core; -import java.util.ArrayList; - import com.vdom.api.Card; -import com.vdom.core.MoveContext; import com.vdom.api.VictoryCard; public class VictoryCardImpl extends CardImpl implements VictoryCard { @@ -33,6 +30,25 @@ public int getVictoryPoints() { return vp; } + @Override + public void play(Game game, MoveContext context) { + play(game, context, true); + } + + @Override + public void play(Game game, MoveContext context, boolean fromHand) { + super.play(game, context, fromHand); + switch (this.getType()) { + case Estate: + if (context.player.getInheritance() != null) { + // TODO + } + break; + default: + break; + } + } + @Override public void isTrashed(MoveContext context) { From f4f55c252b73ecd5f236fabd6697d222634c1b5d Mon Sep 17 00:00:00 2001 From: dominionator Date: Tue, 26 Jan 2016 22:06:14 -0700 Subject: [PATCH 065/141] Bug: fixing Stash AI for when deck shuffled normally. Bug: fixing null inherited card in all cards list --- vdom/src/com/vdom/core/BasePlayer.java | 6 ++++++ vdom/src/com/vdom/core/Player.java | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 0ba797440..0ed87c0e3 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -2709,6 +2709,12 @@ public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { @Override public int stash_chooseDeckPosition(MoveContext context, Card responsible, int deckSize, int numStashes, int cardsToDraw) { + if (responsible == null) { + if (numStashes <= cardsToDraw) + return 0; + return cardsToDraw; + } + if (context.attackedPlayer == this && !Cards.margrave.equals(responsible.behaveAsCard()) && !Cards.soothsayer.equals(responsible.behaveAsCard())) return cardsToDraw; diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 87496d235..f9ec5a3bb 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -661,7 +661,8 @@ public ArrayList getAllCards() { for (Card card : horseTraders) { allCards.add(card); } - allCards.add(inheritance); + if (inheritance != null) + allCards.add(inheritance); if (checkLeadCard != null) { allCards.add(checkLeadCard); } From 73d64bbe009a072a41a38c85bf27cf95b2fb06b6 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 27 Jan 2016 00:01:59 -0700 Subject: [PATCH 066/141] Inheritance: inital work on inheriting play abilities. --- vdom/src/com/vdom/core/ActionCardImpl.java | 42 +++++----- vdom/src/com/vdom/core/CardImpl.java | 39 ++++++++- vdom/src/com/vdom/core/Game.java | 6 +- vdom/src/com/vdom/core/VictoryCardImpl.java | 89 ++++++++++++++++++++- 4 files changed, 144 insertions(+), 32 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 25cce4ba1..1b5869f33 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -209,7 +209,8 @@ public void play(Game game, MoveContext context, boolean fromHand) { Player currentPlayer = context.getPlayer(); boolean newCard = false; - ActionCardImpl actualCard = (this.getControlCard() != null ? (ActionCardImpl) this.getControlCard() : this); + Card actualCard = (this.getControlCard() != null ? this.getControlCard() : this); + boolean isInheritedAbility = actualCard.equals(Cards.estate); context.actions += game.countChampionsInPlay(currentPlayer); @@ -229,11 +230,14 @@ public void play(Game game, MoveContext context, boolean fromHand) { currentPlayer.playedCards.add(this); } } - - GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, (MoveContext) context); - event.card = this; - event.newCard = newCard; - game.broadcastEvent(event); + + GameEvent event; + if (!isInheritedAbility) { + event = new GameEvent(GameEvent.Type.PlayingAction, (MoveContext) context); + event.card = this; + event.newCard = newCard; + game.broadcastEvent(event); + } // playing an action if (this == actualCard) @@ -262,9 +266,13 @@ public void play(Game game, MoveContext context, boolean fromHand) { additionalCardActions(game, context, currentPlayer); - event = new GameEvent(GameEvent.Type.PlayedAction, (MoveContext) context); - event.card = this; - game.broadcastEvent(event); + if (!isInheritedAbility) { + event = new GameEvent(GameEvent.Type.PlayedAction, (MoveContext) context); + event.card = this; + game.broadcastEvent(event); + } else { + return; + } // test if any prince card left the play currentPlayer.princeCardLeftThePlay(currentPlayer); @@ -300,19 +308,6 @@ public void play(Game game, MoveContext context, boolean fromHand) { } } - private boolean isInPlay(Player currentPlayer) { - for (Card c : currentPlayer.playedCards) { - if (this == c) - return true; - } - for (Card c : currentPlayer.nextTurnCards) { - if (c instanceof CardImpl && !((CardImpl)c).trashAfterPlay && this == c) - if (this == c) - return true; - } - return false; - } - protected void additionalCardActions(Game game, MoveContext context, Player currentPlayer) { switch (this.getType()) { case BandOfMisfits: @@ -2152,7 +2147,7 @@ private void horseTradersDungeon(MoveContext context, Player currentPlayer) { cardsToDiscard[i] = hand.get(i); } } else { - cardsToDiscard = currentPlayer.controlPlayer.horseTradersDungeon_cardsToDiscard(context, this.controlCard); + cardsToDiscard = currentPlayer.controlPlayer.horseTradersDungeon_cardsToDiscard(context, this); if (cardsToDiscard == null || cardsToDiscard.length != 2 || !Util.areCardsInHand(cardsToDiscard, context)) { if (currentPlayer.hand.size() >= 2) { Util.playerError(currentPlayer, "Horse Traders discard error, just discarding the first 2."); @@ -5165,6 +5160,7 @@ else if (gainEstates) // card left play - stop any impersonations this.controlCard.stopImpersonatingCard(); + this.controlCard.stopInheritingCardAbilities(); } /*@Override diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 8b8529243..f9496b05d 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -37,6 +37,7 @@ public class CardImpl implements Card { int numberTimesAlreadyPlayed = 0; int cloneCount = 1; CardImpl impersonatingCard = null; + CardImpl inheritingAbilitiesCard = null; CardImpl controlCard = this; protected CardImpl(Cards.Type type, int cost) { @@ -232,6 +233,10 @@ public int getCost(MoveContext context, boolean buyPhase) { if(context.game.getTopKnightCard() != null && !context.game.getTopKnightCard().equals(Cards.virtualKnight)) return context.game.getTopKnightCard().getCost(context,buyPhase); + if (controlCard != null && controlCard != this && controlCard.inheritingAbilitiesCard != null) { + return controlCard.getCost(context, buyPhase); + } + int costModifier = 0; //TODO: BUG this isAction call for Quarry should be player-specific sometimes costModifier -= this.isAction(null) ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; @@ -377,7 +382,7 @@ public boolean isDuration(Player player) { @Override public boolean isAction(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return this instanceof ActionCard; return player.getInheritance() instanceof ActionCard; } @@ -459,21 +464,34 @@ public boolean isImpersonatingAnotherCard() { } public Card behaveAsCard() { - return (this.impersonatingCard == null ? this : this.impersonatingCard); + if (impersonatingCard != null) + return impersonatingCard; + if (inheritingAbilitiesCard != null) + return inheritingAbilitiesCard; + return this; } // CardImpl getImpersonatingCard() { // return impersonatingCard; // } + + void startInheritingCardAbilities(CardImpl inheritingCard) { + inheritingCard.setControlCard(this); + this.inheritingAbilitiesCard = inheritingCard; + } void startImpersonatingCard(CardImpl impersonatingCard) { impersonatingCard.setControlCard(this); this.impersonatingCard = impersonatingCard; - } + } void stopImpersonatingCard() { this.impersonatingCard = null; - } + } + + void stopInheritingCardAbilities() { + this.inheritingAbilitiesCard = null; + } @Override public CardImpl getControlCard() { @@ -511,6 +529,19 @@ protected void attackPlayed(MoveContext context, Game game, Player currentPlayer } } } + + protected boolean isInPlay(Player currentPlayer) { + for (Card c : currentPlayer.playedCards) { + if (this == c) + return true; + } + for (Card c : currentPlayer.nextTurnCards) { + if (c instanceof CardImpl && !((CardImpl)c).trashAfterPlay && this == c) + if (this == c) + return true; + } + return false; + } /*@Override public void isGained(MoveContext context) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 8ed56aa36..8d57e5737 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -694,7 +694,7 @@ protected void playerAction(Player player, MoveContext context) { broadcastEvent(event); try { - ((ActionCardImpl) action).play(this, (MoveContext) context, true); + action.play(this, (MoveContext) context, true); } catch (RuntimeException e) { e.printStackTrace(); } @@ -924,7 +924,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { context.freeActionInEffect++; try { - ((ActionCardImpl) card2).play(this, context, false); + card2.play(this, context, false); } catch (RuntimeException e) { e.printStackTrace(); } @@ -934,7 +934,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { context.freeActionInEffect++; try { - ((ActionCardImpl) card2).play(this, context, false); + card2.play(this, context, false); } catch (RuntimeException e) { e.printStackTrace(); } diff --git a/vdom/src/com/vdom/core/VictoryCardImpl.java b/vdom/src/com/vdom/core/VictoryCardImpl.java index dc3e26e17..168657308 100644 --- a/vdom/src/com/vdom/core/VictoryCardImpl.java +++ b/vdom/src/com/vdom/core/VictoryCardImpl.java @@ -1,6 +1,10 @@ package com.vdom.core; +import java.util.ArrayList; +import java.util.Collections; + import com.vdom.api.Card; +import com.vdom.api.GameEvent; import com.vdom.api.VictoryCard; public class VictoryCardImpl extends CardImpl implements VictoryCard { @@ -38,10 +42,91 @@ public void play(Game game, MoveContext context) { @Override public void play(Game game, MoveContext context, boolean fromHand) { super.play(game, context, fromHand); + Player currentPlayer = context.getPlayer(); switch (this.getType()) { case Estate: - if (context.player.getInheritance() != null) { - // TODO + Card inheritedCard = context.player.getInheritance(); + if (inheritedCard != null) { + // TODO + boolean newCard = false; + if (this.numberTimesAlreadyPlayed == 0) { + newCard = true; + this.movedToNextTurnPile = false; + if (fromHand) + currentPlayer.hand.remove(this); + currentPlayer.playedCards.add(this); + } + + GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, (MoveContext) context); + event.card = this; + event.newCard = newCard; + game.broadcastEvent(event); + + context.actionsPlayedSoFar++; + if (context.freeActionInEffect == 0) { + context.actions--; + } + + this.startInheritingCardAbilities(inheritedCard.getTemplateCard().instantiate()); + // Play the inheritance virtual card + ActionCardImpl cardToPlay = (ActionCardImpl) this.behaveAsCard(); + context.freeActionInEffect++; + cardToPlay.play(game, context, false); + context.freeActionInEffect--; + + // impersonated card stays in play until next turn? + if (cardToPlay.trashOnUse) { + int idx = currentPlayer.playedCards.lastIndexOf(this); + if (idx >= 0) currentPlayer.playedCards.remove(idx); + currentPlayer.trash(this, null, context); + } else if (cardToPlay.isDuration(currentPlayer) && !cardToPlay.equals(Cards.outpost)) { + if (!this.controlCard.movedToNextTurnPile) { + this.controlCard.movedToNextTurnPile = true; + int idx = currentPlayer.playedCards.lastIndexOf(this); + if (idx >= 0) { + currentPlayer.playedCards.remove(idx); + currentPlayer.nextTurnCards.add(this); + } + } + } + + event = new GameEvent(GameEvent.Type.PlayedAction, (MoveContext) context); + event.card = this; + game.broadcastEvent(event); + + // test if any prince card left the play + currentPlayer.princeCardLeftThePlay(currentPlayer); + + // check for cards to call after resolving action + boolean isActionInPlay = isInPlay(currentPlayer); + ArrayList callableCards = new ArrayList(); + CallableCard toCall = null; + for (Card c : currentPlayer.tavern) { + if (c.behaveAsCard() instanceof CallableCard) { + CallableCard card = (CallableCard)(c.behaveAsCard()); + if (!card.isCallableWhenActionResolved() || (card.doesActionStillNeedToBeInPlay() && !isActionInPlay)) + continue; + callableCards.add((CallableCard) c); + } + } + if (!callableCards.isEmpty()) { + Collections.sort(callableCards, new Util.CardCostComparator()); + do { + toCall = null; + // we want null entry at the end for None + CallableCard[] cardsAsArray = callableCards.toArray(new CallableCard[callableCards.size() + 1]); + //ask player which card to call + toCall = currentPlayer.controlPlayer.call_whenActionResolveCardToCall(context, this, cardsAsArray); + if (toCall != null && callableCards.contains(toCall)) { + callableCards.remove(toCall); + toCall.callWhenActionResolved(context, this); + } + // loop while we still have cards to call + // NOTE: we have a hack here to prevent asking for duplicate calls on an unused Royal Carriage + // since technically you can ask for more and action re-played by royal carriage will ask as well + } while (toCall != null && toCall.equals(Cards.coinOfTheRealm) && !callableCards.isEmpty()); + } + } break; default: From 6c46a3708219223cfe3d19a119d3ef158cf60ef0 Mon Sep 17 00:00:00 2001 From: dominionator Date: Wed, 27 Jan 2016 20:54:38 -0700 Subject: [PATCH 067/141] Inheritance: enabling Inherited when-buy abilities Fixing Inherited type checks. --- vdom/src/com/vdom/api/Card.java | 2 +- vdom/src/com/vdom/core/ActionCardImpl.java | 2 +- vdom/src/com/vdom/core/CardImpl.java | 19 ++++++++++--------- vdom/src/com/vdom/core/Game.java | 12 +++++++++--- vdom/src/com/vdom/core/RemotePlayer.java | 2 +- vdom/src/com/vdom/core/VictoryCardImpl.java | 9 +++++++-- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/vdom/src/com/vdom/api/Card.java b/vdom/src/com/vdom/api/Card.java index 940dc03ea..aa8effe57 100644 --- a/vdom/src/com/vdom/api/Card.java +++ b/vdom/src/com/vdom/api/Card.java @@ -46,7 +46,7 @@ public interface Card extends Serializable { public boolean isKnight(Player player); - public boolean isOverpay(); + public boolean isOverpay(Player player); public boolean isEvent(); diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 1b5869f33..011492d22 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -6235,7 +6235,7 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) private void messenger(Game game, MoveContext context, Player currentPlayer) { if (currentPlayer.getDeckSize() == 0) return; - boolean discard = currentPlayer.controlPlayer.messenger_shouldDiscardDeck(context, this.controlCard); + boolean discard = currentPlayer.controlPlayer.messenger_shouldDiscardDeck(context, this); if (discard) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index f9496b05d..2682b6308 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -375,7 +375,7 @@ public boolean costPotion() { @Override public boolean isDuration(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return this instanceof DurationCard; return player.getInheritance() instanceof DurationCard; } @@ -389,7 +389,7 @@ public boolean isAction(Player player) { @Override public boolean isAttack(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return isAttack; return ((CardImpl)player.getInheritance()).isAttack; } @@ -403,13 +403,13 @@ public boolean isShelter() { } @Override public boolean isRuins(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return isRuins; return ((CardImpl)player.getInheritance()).isRuins; } @Override public boolean isKnight(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return isKnight; return ((CardImpl)player.getInheritance()).isKnight; } @@ -420,9 +420,10 @@ public boolean isLooter() { } @Override - public boolean isOverpay() - { - return isOverpay; + public boolean isOverpay(Player player) { + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) + return isOverpay; + return ((CardImpl)player.getInheritance()).isOverpay; } @Override @@ -434,7 +435,7 @@ public boolean isEvent() @Override public boolean isReserve(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return isReserve; return ((CardImpl)player.getInheritance()).isReserve; } @@ -442,7 +443,7 @@ public boolean isReserve(Player player) @Override public boolean isTraveller(Player player) { - if (player == null || player.getInheritance() == null) + if (player == null || player.getInheritance() == null || !this.equals(Cards.estate)) return isTraveller; return ((CardImpl)player.getInheritance()).isTraveller; } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 8d57e5737..117af1a24 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -1528,13 +1528,19 @@ Card playBuy(MoveContext context, Card buy) { int cost = buy.getCost(context); // If card can be overpaid for, do so now - if (buy.isOverpay()) + if (buy.isOverpay(player)) { - context.overpayAmount = player.amountToOverpay(context, buy, cost); + int coinOverpay = player.amountToOverpay(context, buy, cost); + coinOverpay = Math.max(0, coinOverpay); + coinOverpay = Math.min(coinOverpay, context.getCoinAvailableForBuy()); + context.overpayAmount = coinOverpay; if (context.potions > 0) { - context.overpayPotions = player.overpayByPotions(context, context.potions); + int potionOverpay = player.overpayByPotions(context, context.potions); + potionOverpay = Math.max(0, potionOverpay); + potionOverpay = Math.min(potionOverpay, context.getPotions()); + context.overpayPotions = potionOverpay; context.potions -= context.overpayPotions; } diff --git a/vdom/src/com/vdom/core/RemotePlayer.java b/vdom/src/com/vdom/core/RemotePlayer.java index 3357cc7c8..49ea39243 100644 --- a/vdom/src/com/vdom/core/RemotePlayer.java +++ b/vdom/src/com/vdom/core/RemotePlayer.java @@ -111,7 +111,7 @@ public static MyCard makeMyCard(Card c, int index, boolean isBane, boolean isBla card.isBane = isBane; card.isShelter = c.isShelter(); card.isLooter = c.isLooter(); - card.isOverpay = c.isOverpay(); + card.isOverpay = c.isOverpay(null); card.isEvent = c.isEvent(); card.isReserve = c.isReserve(null); card.isTraveller = c.isTraveller(null); diff --git a/vdom/src/com/vdom/core/VictoryCardImpl.java b/vdom/src/com/vdom/core/VictoryCardImpl.java index 168657308..7df1d07ed 100644 --- a/vdom/src/com/vdom/core/VictoryCardImpl.java +++ b/vdom/src/com/vdom/core/VictoryCardImpl.java @@ -170,8 +170,13 @@ protected VictoryCardImpl() { @Override public void isBuying(MoveContext context) { context.game.trashHovelsInHandOption(context.player, context, this); - - if (this.equals(Cards.farmland)) { + + if (this.equals(Cards.estate)) { + Card inheritance = context.getPlayer().getInheritance(); + if (inheritance != null) { + inheritance.isBuying(context); + } + } else if (this.equals(Cards.farmland)) { Player player = context.getPlayer(); if(player.getHand().size() > 0) { Card cardToTrash = player.controlPlayer.farmland_cardToTrash((MoveContext) context); From 6df9e29581ffd38a6ccf670e8e5ee0300162d7a9 Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 28 Jan 2016 00:10:07 -0700 Subject: [PATCH 068/141] Inheritance: Adding Inherited when-gain abilities. Changing string for coin tokens to be called "Coin token" instead of "Guilds token". Fixed bug for looter type not being added (caused Ruins not to be added). --- .../res/values/strings-preferences.xml | 4 +- androminion/res/values/strings-server.xml | 6 +-- vdom/src/com/vdom/core/ActionCardImpl.java | 9 ----- vdom/src/com/vdom/core/BasePlayer.java | 4 +- vdom/src/com/vdom/core/Cards.java | 6 +-- vdom/src/com/vdom/core/Game.java | 40 ++++++++++++------- vdom/src/com/vdom/core/IndirectPlayer.java | 8 ++-- vdom/src/com/vdom/core/QuickPlayPlayer.java | 2 +- .../com/vdom/players/VDomPlayerPatrick.java | 4 +- 9 files changed, 43 insertions(+), 40 deletions(-) diff --git a/androminion/res/values/strings-preferences.xml b/androminion/res/values/strings-preferences.xml index 562534a9d..acaa4529b 100644 --- a/androminion/res/values/strings-preferences.xml +++ b/androminion/res/values/strings-preferences.xml @@ -22,8 +22,8 @@ Display the system status bar while playing Game Play Test-Modus - Guilds coin tokens - Start with Guilds coin tokens instead of cards + Coin tokens + Start with Coin tokens instead of cards Less provinces Play with less provinces Quick play diff --git a/androminion/res/values/strings-server.xml b/androminion/res/values/strings-server.xml index 4569da896..97460cc30 100644 --- a/androminion/res/values/strings-server.xml +++ b/androminion/res/values/strings-server.xml @@ -134,8 +134,8 @@ Playing duration Playing Buying - Guilds token obtained - Guilds token paid + Coin token obtained + Coin token spent Overpay for card (No buy) Deck replenished @@ -421,7 +421,7 @@ Discard Put Back Select card to put back on deck - Spend Guilds Coin Tokens + Spend Coin Tokens Overpay? Overpay by Potion(s)? possessed by diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 011492d22..398c7f67c 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -31,7 +31,6 @@ public class ActionCardImpl extends CardImpl implements ActionCard { protected int addCards; protected int addGold; protected int addVictoryTokens; - protected boolean looter; boolean trashForced = false; boolean trashOnUse = false; @@ -42,7 +41,6 @@ public ActionCardImpl(Builder builder) { addCards = builder.addCards; addGold = builder.addGold; addVictoryTokens = builder.addVictoryTokens; - looter = builder.looter; trashOnUse = builder.trashOnUse; trashForced = builder.trashForced; } @@ -53,7 +51,6 @@ public static class Builder extends CardImpl.Builder{ protected int addCards; protected int addGold; protected int addVictoryTokens; - protected boolean looter; protected boolean trashOnUse; protected boolean trashForced = false; @@ -86,11 +83,6 @@ public Builder addVictoryTokens(int val) { return this; } - public Builder looter() { - looter = true; - return this; - } - public Builder trashOnUse() { trashOnUse = true; return this; @@ -192,7 +184,6 @@ protected void copyValues(ActionCardImpl c) { c.addCards = addCards; c.addGold = addGold; c.addVictoryTokens = addVictoryTokens; - c.looter = looter; c.trashForced = trashForced; c.trashOnUse = trashOnUse; } diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 0ed87c0e3..0c8e073a6 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -2194,8 +2194,8 @@ public boolean inn_shuffleCardBackIntoDeck(MoveContext context, Card card) { } @Override - public Card borderVillage_cardToObtain(MoveContext context) { - return bestCardInPlay(context, Cards.borderVillage.getCost(context) - 1, true); + public Card borderVillage_cardToObtain(MoveContext context, int maxCost) { + return bestCardInPlay(context, maxCost, true); } @Override diff --git a/vdom/src/com/vdom/core/Cards.java b/vdom/src/com/vdom/core/Cards.java index 7c80f14f9..183919b7f 100644 --- a/vdom/src/com/vdom/core/Cards.java +++ b/vdom/src/com/vdom/core/Cards.java @@ -628,8 +628,8 @@ public enum Type { actionCardsDarkAges.add(catacombs = new ActionCardImpl.Builder(Cards.Type.Catacombs, 5).description("Look at the top 3 cards of your deck. Choose one: Put them into your hand; or discard them and +3 Cards. When you trash this, gain a cheaper card.").expansion("DarkAges").build()); actionCardsDarkAges.add(count = new ActionCardImpl.Builder(Cards.Type.Count, 5).description("Choose one: Discard 2 cards; or put a card from your hand on top of your deck; or gain a Copper. Choose one: +3 coins; or trash your hand; or gain a Duchy.").expansion("DarkAges").build()); actionCardsDarkAges.add(counterfeit = new TreasureCardImpl.Builder(Cards.Type.Counterfeit, 5, 1).description("+1 Buy\nWhen you play this, you may play a Treasure from your hand twice. If you do, trash that Treasure.").expansion("DarkAges").build()); - actionCardsDarkAges.add(cultist = new ActionCardImpl.Builder(Cards.Type.Cultist, 5).looter().addCards(2).attack().description("Each other player gains a Ruins. You may play a Cultist from your hand. When you trash this, +3 Cards.").expansion("DarkAges").build()); - actionCardsDarkAges.add(deathCart = new ActionCardImpl.Builder(Cards.Type.DeathCart, 4).addGold(5).looter().description("You may trash an Action card from your hand. If you don't, trash this. When you gain this, gain 2 Ruins.").expansion("DarkAges").build()); + actionCardsDarkAges.add(cultist = new ActionCardImpl.Builder(Cards.Type.Cultist, 5).addCards(2).attack().isLooter().description("Each other player gains a Ruins. You may play a Cultist from your hand. When you trash this, +3 Cards.").expansion("DarkAges").build()); + actionCardsDarkAges.add(deathCart = new ActionCardImpl.Builder(Cards.Type.DeathCart, 4).addGold(5).isLooter().description("You may trash an Action card from your hand. If you don't, trash this. When you gain this, gain 2 Ruins.").expansion("DarkAges").build()); actionCardsDarkAges.add(feodum = new VictoryCardImpl.Builder(Cards.Type.Feodum, 4, 0).description("Worth 1 VP for every 3 Silvers in your deck (round down). When you trash this, gain 3 Silvers.").expansion("DarkAges").build()); actionCardsDarkAges.add(forager = new ActionCardImpl.Builder(Cards.Type.Forager, 3).addActions(1).addBuys(1).trashForced().description("Trash a card from your hand. +1 coin per differently named Treasure in the trash.").expansion("DarkAges").build()); actionCardsDarkAges.add(fortress = new ActionCardImpl.Builder(Cards.Type.Fortress, 4).addCards(1).addActions(2).description("When you trash this, put it into your hand.").expansion("DarkAges").build()); @@ -638,7 +638,7 @@ public enum Type { actionCardsDarkAges.add(huntingGrounds = new ActionCardImpl.Builder(Cards.Type.HuntingGrounds, 6).addCards(4).description("When you trash this, gain a Duchy or 3 Estates.").expansion("DarkAges").build()); actionCardsDarkAges.add(ironmonger = new ActionCardImpl.Builder(Cards.Type.Ironmonger, 4).addCards(1).addActions(1).description("Reveal the top card of your deck; you may discard it. Either way, if it is an Action card, +1 Action; Treasure card, + 1 coin; Victory card, +1 Card.").expansion("DarkAges").build()); actionCardsDarkAges.add(junkDealer = new ActionCardImpl.Builder(Cards.Type.JunkDealer, 5).addCards(1).addActions(1).addGold(1).trashForced().description("Trash a card from your hand.").expansion("DarkAges").build()); - actionCardsDarkAges.add(marauder = new ActionCardImpl.Builder(Cards.Type.Marauder, 4).looter().attack().description("Gain a Spoils from the Spoils pile. Each other player gains a Ruins.").expansion("DarkAges").build()); + actionCardsDarkAges.add(marauder = new ActionCardImpl.Builder(Cards.Type.Marauder, 4).attack().isLooter().description("Gain a Spoils from the Spoils pile. Each other player gains a Ruins.").expansion("DarkAges").build()); actionCardsDarkAges.add(marketSquare = new ActionCardImpl.Builder(Cards.Type.MarketSquare, 3).addCards(1).addActions(1).addBuys(1).description("When one of your cards is trashed, you may discard this from your hand. If you do, gain a Gold.").expansion("DarkAges").build()); actionCardsDarkAges.add(mystic = new ActionCardImpl.Builder(Cards.Type.Mystic, 5).addActions(1).addGold(2).description("Name a card. Reveal the top card of your deck. If it’s the named card, put it into your hand.").expansion("DarkAges").build()); actionCardsDarkAges.add(pillage = new ActionCardImpl.Builder(Cards.Type.Pillage, 5).trashOnUse().attack().description("Trash this. Each other player with 5 or more cards in hand reveals his hand and discards a card that you choose. Gain 2 Spoils from the Spoils pile.").expansion("DarkAges").build()); diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 117af1a24..5cc0214d2 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -2519,6 +2519,9 @@ public void gameEvent(GameEvent event) { commandedDiscard = false; } else if(event.responsible != null) { Card r = event.responsible; + if (r.equals(Cards.estate) && player.getInheritance() != null) { + r = player.getInheritance(); + } if(r.equals(Cards.borderVillage) || r.equals(Cards.feast) || r.equals(Cards.remodel) || @@ -2584,6 +2587,11 @@ public void gameEvent(GameEvent event) { player.trash(event.card, Cards.watchTower, context); } } + + Card gainedCardAbility = event.card; + if (gainedCardAbility.equals(Cards.estate) && player.getInheritance() != null) { + gainedCardAbility = player.getInheritance(); + } if(!handled) { if (context.isRoyalSealInPlay() && context.player.controlPlayer.royalSealTravellingFair_shouldPutCardOnDeck((MoveContext) context, Cards.royalSeal, event.card)) { @@ -2601,10 +2609,14 @@ public void gameEvent(GameEvent event) { GameEvent summonEvent = new GameEvent(GameEvent.Type.CardSetAsideSummon, context); summonEvent.card = event.card; context.game.broadcastEvent(summonEvent); - } else if (event.card.equals(Cards.nomadCamp)) { + } else if (gainedCardAbility.equals(Cards.nomadCamp)) { player.putOnTopOfDeck(event.card, context, true); } else if (event.responsible != null) { Card r = event.responsible; + if (r.equals(Cards.estate) && player.getInheritance() != null) { + r = player.getInheritance(); + } + if (r.equals(Cards.armory) || r.equals(Cards.artificer) || r.equals(Cards.bagOfGold) @@ -2662,8 +2674,8 @@ public void gameEvent(GameEvent event) { toCall.callWhenCardGained(context, event.card); } } - - if (event.card.equals(Cards.illGottenGains)) { + + if (gainedCardAbility.equals(Cards.illGottenGains)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { MoveContext targetContext = new MoveContext(Game.this, targetPlayer); @@ -2697,18 +2709,18 @@ public void gameEvent(GameEvent event) { player.gainNewCard(Cards.duchess, Cards.duchess, context); } } - } else if(event.card.equals(Cards.embassy)) { + } else if(gainedCardAbility.equals(Cards.embassy)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { MoveContext targetContext = new MoveContext(Game.this, targetPlayer); targetPlayer.gainNewCard(Cards.silver, event.card, targetContext); } } - } else if(event.card.equals(Cards.cache)) { + } else if(gainedCardAbility.equals(Cards.cache)) { for(int i=0; i < 2; i++) { player.gainNewCard(Cards.copper, event.card, context); } - } else if(event.card.equals(Cards.inn)) { + } else if(gainedCardAbility.equals(Cards.inn)) { ArrayList cards = new ArrayList(); int actionCardsFound = 0; for(int i=player.discard.size() - 1; i >= 0; i--) { @@ -2729,20 +2741,20 @@ public void gameEvent(GameEvent event) { } } player.shuffleDeck(context, event.card); - } else if (event.card.equals(Cards.borderVillage)) { + } else if (gainedCardAbility.equals(Cards.borderVillage)) { boolean validCard = false; - + int gainedCardCost = event.card.getCost(context); for(Card c : event.context.getCardsInGame()) { - if(Cards.isSupplyCard(c) && c.getCost(context) < Cards.borderVillage.getCost(context) && !c.costPotion() && event.context.getCardsLeftInPile(c) > 0) { + if(Cards.isSupplyCard(c) && c.getCost(context) < gainedCardCost && !c.costPotion() && event.context.getCardsLeftInPile(c) > 0) { validCard = true; break; } } if(validCard) { - Card card = context.player.controlPlayer.borderVillage_cardToObtain((MoveContext) context); + Card card = context.player.controlPlayer.borderVillage_cardToObtain(context, gainedCardCost - 1); if (card != null) { - if(card.getCost(context) < Cards.borderVillage.getCost(context) && !card.costPotion()) { + if(card.getCost(context) < gainedCardCost && !card.costPotion()) { player.controlPlayer.gainNewCard(card, event.card, (MoveContext) context); } else { @@ -2750,7 +2762,7 @@ public void gameEvent(GameEvent event) { } } } - } else if (event.card.equals(Cards.mandarin)) { + } else if (gainedCardAbility.equals(Cards.mandarin)) { CardList playedCards = ((MoveContext) context).getPlayedCards(); ArrayList treasureCardsInPlay = new ArrayList(); @@ -2773,10 +2785,10 @@ public void gameEvent(GameEvent event) { playedCards.remove(c); } } - } else if (event.card.equals(Cards.deathCart)) { + } else if (gainedCardAbility.equals(Cards.deathCart)) { context.player.controlPlayer.gainNewCard(Cards.virtualRuins, event.card, context); context.player.controlPlayer.gainNewCard(Cards.virtualRuins, event.card, context); - } else if(event.card.equals(Cards.lostCity)) { + } else if (gainedCardAbility.equals(Cards.lostCity)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { drawToHand(new MoveContext(Game.this, targetPlayer), event.card, 1, true); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index f1fe04121..0698269b7 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -1725,12 +1725,12 @@ public boolean inn_shuffleCardBackIntoDeck(MoveContext context, Card card) { } @Override - public Card borderVillage_cardToObtain(MoveContext context) { - if(context.isQuickPlay() && shouldAutoPlay_borderVillage_cardToObtain(context)) { - return super.borderVillage_cardToObtain(context); + public Card borderVillage_cardToObtain(MoveContext context, int maxCost) { + if(context.isQuickPlay() && shouldAutoPlay_borderVillage_cardToObtain(context, maxCost)) { + return super.borderVillage_cardToObtain(context, maxCost); } SelectCardOptions sco = new SelectCardOptions().potionCost(0) - .maxCost(Cards.borderVillage.getCost(context) - 1) + .maxCost(maxCost) .setActionType(ActionType.GAIN).setCardResponsible(Cards.borderVillage); return getFromTable(context, sco); } diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 971773a07..881ab72b6 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -748,7 +748,7 @@ public boolean shouldAutoPlay_stables_treasureToDiscard(MoveContext context) { return true; } - public boolean shouldAutoPlay_borderVillage_cardToObtain(MoveContext context) { + public boolean shouldAutoPlay_borderVillage_cardToObtain(MoveContext context, int maxCost) { return false; } diff --git a/vdom/src/com/vdom/players/VDomPlayerPatrick.java b/vdom/src/com/vdom/players/VDomPlayerPatrick.java index e5bc7aaec..10d5db6de 100644 --- a/vdom/src/com/vdom/players/VDomPlayerPatrick.java +++ b/vdom/src/com/vdom/players/VDomPlayerPatrick.java @@ -1151,9 +1151,9 @@ public Card farmland_cardToTrash(MoveContext context) { } @Override - public Card borderVillage_cardToObtain(MoveContext context) { + public Card borderVillage_cardToObtain(MoveContext context, int maxCost) { this.log("borderVillage_cardToObtain"); - return this.advisorGeneral(context, 5, false, true); + return this.advisorGeneral(context, maxCost, false, true); } @Override From e0df23b862b1820b6454da2667b6dca0b27a21b1 Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 28 Jan 2016 01:37:17 -0700 Subject: [PATCH 069/141] Inheritance: Adding inherited "While this is in play..." abilities. Fixing costs related to Bridge Troll to apply correctly. Committing missing file change to Player border village interaction. --- vdom/src/com/vdom/core/CardImpl.java | 12 ++++++++---- vdom/src/com/vdom/core/MoveContext.java | 8 ++++---- vdom/src/com/vdom/core/Player.java | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/vdom/src/com/vdom/core/CardImpl.java b/vdom/src/com/vdom/core/CardImpl.java index 2682b6308..11e6dc0b2 100644 --- a/vdom/src/com/vdom/core/CardImpl.java +++ b/vdom/src/com/vdom/core/CardImpl.java @@ -237,17 +237,21 @@ public int getCost(MoveContext context, boolean buyPhase) { return controlCard.getCost(context, buyPhase); } + MoveContext currentPlayerContext = context; + if (context.game.getCurrentPlayer() != context.getPlayer()) { + currentPlayerContext = new MoveContext(context.game, context.game.getCurrentPlayer()); + } + int costModifier = 0; //TODO: BUG this isAction call for Quarry should be player-specific sometimes costModifier -= this.isAction(null) ? (2 * context.countCardsInPlay(Cards.quarry)) : 0; costModifier -= context.countCardsInPlay(Cards.highway); - costModifier -= context.countCardsInPlay(Cards.bridgeTroll); - costModifier -= context.countCardsInNextTurn(Cards.bridgeTroll); + costModifier -= currentPlayerContext.countCardsInPlay(Cards.bridgeTroll); costModifier -= 2 * context.countCardsInPlay(Cards.princess); + //TODO: BUG if an inherited peddler is yours, its cost should lower during your buy phase costModifier -= (buyPhase && this.equals(Cards.peddler)) ? (2 * context.countActionCardsInPlayThisTurn()) : 0; costModifier -= (context.game.isPlayerSupplyTokenOnPile(this, context.game.getCurrentPlayer(), PlayerSupplyToken.MinusTwoCost)) ? 2 : 0; - //costModifier -= (this.isKnight ? (cost - game. (2 * context.countCardsInPlay(Cards.quarry)) : 0; - + return Math.max(0, cost + costModifier + context.cardCostModifier/*bridge*/); } diff --git a/vdom/src/com/vdom/core/MoveContext.java b/vdom/src/com/vdom/core/MoveContext.java index 1eaec2a68..533b9a361 100644 --- a/vdom/src/com/vdom/core/MoveContext.java +++ b/vdom/src/com/vdom/core/MoveContext.java @@ -109,14 +109,14 @@ public int countCardsInPlay(Card card) { cardsInPlay++; } } - return cardsInPlay; + return cardsInPlay + countCardsInNextTurn(card); } public CardList getCardsInNextTurn() { return player.nextTurnCards; } - public int countCardsInNextTurn(Card card) { + private int countCardsInNextTurn(Card card) { int cardsInNextTurn = 0; for(Card c : getCardsInNextTurn()) { if(c.behaveAsCard().equals(card)) { @@ -131,7 +131,7 @@ public boolean isRoyalSealInPlay() { } public int countGoonsInPlayThisTurn() { - return countCardsInPlay(Cards.goons); + return countCardsInPlay(Cards.goons); } public int countTreasureCardsInPlayThisTurn() { @@ -439,6 +439,6 @@ protected Card[] getAvailableCards(int cost, boolean potion) { } public int countMerchantGuildsInPlayThisTurn() { - return countCardsInPlay(Cards.merchantGuild); + return countCardsInPlay(Cards.merchantGuild); } } diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index f9ec5a3bb..d02a3a810 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1649,7 +1649,7 @@ public ArrayList getActionsInHand(Player player) { // //////////////////////////////////////////// // Card interactions - cards from Hinterlands // //////////////////////////////////////////// - public abstract Card borderVillage_cardToObtain(MoveContext context); + public abstract Card borderVillage_cardToObtain(MoveContext context, int maxCost); public abstract Card farmland_cardToTrash(MoveContext context); From 2670f2055db0b2bc57077a2cf7510ff90c0226f9 Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 28 Jan 2016 22:06:25 -0700 Subject: [PATCH 070/141] Inheritance: Making sure correct card ability name gets passed to UI. --- vdom/src/com/vdom/core/ActionCardImpl.java | 292 +++++++++---------- vdom/src/com/vdom/core/BasePlayer.java | 38 ++- vdom/src/com/vdom/core/EventCardImpl.java | 2 +- vdom/src/com/vdom/core/Game.java | 4 +- vdom/src/com/vdom/core/IndirectPlayer.java | 58 ++-- vdom/src/com/vdom/core/Player.java | 8 +- vdom/src/com/vdom/core/QuickPlayPlayer.java | 17 +- vdom/src/com/vdom/core/TreasureCardImpl.java | 4 +- 8 files changed, 235 insertions(+), 188 deletions(-) diff --git a/vdom/src/com/vdom/core/ActionCardImpl.java b/vdom/src/com/vdom/core/ActionCardImpl.java index 398c7f67c..8ba82641f 100644 --- a/vdom/src/com/vdom/core/ActionCardImpl.java +++ b/vdom/src/com/vdom/core/ActionCardImpl.java @@ -893,7 +893,7 @@ private void warehouse(MoveContext context, Player currentPlayer) { private void cutpurse(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -982,7 +982,7 @@ private void embargo(Game game, MoveContext context, Player currentPlayer) { private void navigator(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = game.draw(context, controlCard, 5 - i); + Card card = game.draw(context, Cards.navigator, 5 - i); if (card != null) { topOfTheDeck.add(card); } @@ -1035,7 +1035,7 @@ private void navigator(Game game, MoveContext context, Player currentPlayer) { private void lookout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(context, controlCard, 3 - i); + Card card = game.draw(context, Cards.lookout, 3 - i); if (card != null) { cards.add(card); } @@ -1088,7 +1088,7 @@ private void lookout(Game game, MoveContext context, Player currentPlayer) { private void pearlDiver(MoveContext context, Player currentPlayer) { if (currentPlayer.getDeckSize() == 0 && currentPlayer.discard.size() > 0) { - context.game.replenishDeck(context, controlCard, 0); + context.game.replenishDeck(context, Cards.pearlDiver, 0); } if (currentPlayer.getDeckSize() > 1) { @@ -1241,7 +1241,7 @@ private void nativeVillage(Game game, MoveContext context, Player currentPlayer) currentPlayer.hand.add(currentPlayer.nativeVillage.remove(0)); } } else { - Card draw = game.draw(context, controlCard, 1); + Card draw = game.draw(context, Cards.nativeVillage, 1); if (draw != null) { currentPlayer.nativeVillage.add(draw); Util.sensitiveDebug(currentPlayer, "Added to Native Village:" + draw.getName(), true); @@ -1251,12 +1251,12 @@ private void nativeVillage(Game game, MoveContext context, Player currentPlayer) private void seaHag(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card draw = game.draw(playerContext, controlCard, 1); + Card draw = game.draw(playerContext, Cards.seaHag, 1); if (draw != null) { player.discard(draw, this.controlCard, playerContext); } @@ -1269,7 +1269,7 @@ private void seaHag(Game game, MoveContext context, Player currentPlayer) { private void councilRoom(Game game, MoveContext context) { for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - game.drawToHand(new MoveContext(game, player), this.controlCard, 1); + game.drawToHand(new MoveContext(game, player), this, 1); } } } @@ -1330,7 +1330,7 @@ private void apprentice(Game game, MoveContext context, Player currentPlayer) { int cardsToDraw = (cardToTrash.getCost(context) + (cardToTrash.costPotion() ? 2 : 0)); for (int i = 1; i <= cardsToDraw; i++) { - game.drawToHand(context, this.controlCard, cardsToDraw - i); + game.drawToHand(context, this, cardsToDraw - i); } } } @@ -1359,7 +1359,7 @@ private void transmute(MoveContext context, Player currentPlayer) { private void apothecary(Game game, MoveContext context, Player currentPlayer) { ArrayList residue = new ArrayList(); for (int i = 1; i <= 4; i++) { - Card card = game.draw(context, controlCard, 4 - i); + Card card = game.draw(context, Cards.apothecary, 4 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); if (card.equals(Cards.copper) || card.equals(Cards.potion)) { @@ -1384,7 +1384,7 @@ private void apothecary(Game game, MoveContext context, Player currentPlayer) { private void witchFamiliar(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, player); targetContext.attackedPlayer = player; @@ -1413,7 +1413,7 @@ private void tactician(MoveContext context, Player currentPlayer) { private void torturer(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, targetPlayer); playerContext.attackedPlayer = targetPlayer; @@ -1475,7 +1475,7 @@ private void torturer(Game game, MoveContext context, Player currentPlayer) { private void scout(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(context, controlCard, 4 - i); + Card card = game.draw(context, Cards.scout, 4 - i); if (card == null) { break; } @@ -1581,7 +1581,7 @@ private void ambassador(Game game, MoveContext context, Player currentPlayer) { /* Even if revealed Shelters, opponents may react */ for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); if (returnCount > -1) { @@ -1595,7 +1595,7 @@ private void ambassador(Game game, MoveContext context, Player currentPlayer) { private void ghostShip(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -1683,7 +1683,7 @@ private void bishop(Game game, MoveContext context, Player currentPlayer) { private void city(Game game, MoveContext context, Player currentPlayer) { if (game.emptyPiles() > 0) { - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 1); } if (game.emptyPiles() > 1) { context.buys++; @@ -1877,7 +1877,7 @@ else if (cardToMint != null) { private void mountebank(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -1903,7 +1903,7 @@ private void mountebank(Game game, MoveContext context, Player currentPlayer) { private void rabble(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -1911,7 +1911,7 @@ private void rabble(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(playerContext, controlCard, 3 - i); + Card card = game.draw(playerContext, Cards.rabble, 3 - i); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -2029,7 +2029,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { } if (numberOfCardsDiscarded == 2) { - game.drawToHand(playerContext, this.controlCard, 1); + game.drawToHand(playerContext, this, 1); } } } @@ -2039,7 +2039,7 @@ private void vault(Game game, MoveContext context, Player currentPlayer) { private void watchTower(Game game, MoveContext context, Player currentPlayer) { int cardsToDraw = 6 - currentPlayer.hand.size(); for (int i = 0; i < cardsToDraw; ++i) { - if(!game.drawToHand(context, this.controlCard, cardsToDraw - i)) + if(!game.drawToHand(context, this, cardsToDraw - i)) break; } } @@ -2049,7 +2049,7 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer ArrayList toDiscard = new ArrayList(); - while ((draw = game.draw(context, controlCard, -1)) != null && !(draw.isAction(currentPlayer)) && !(draw instanceof TreasureCard)) { + while ((draw = game.draw(context, Cards.farmingVillage, -1)) != null && !(draw.isAction(currentPlayer)) && !(draw instanceof TreasureCard)) { toDiscard.add(draw); } @@ -2067,14 +2067,14 @@ private void farmingVillage(Game game, MoveContext context, Player currentPlayer private void fortuneTeller(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; ArrayList cardsToDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(playerContext, controlCard, -1)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { + while ((draw = game.draw(playerContext, Cards.fortuneTeller, -1)) != null && !(draw instanceof VictoryCard) && !(draw instanceof CurseCard)) { player.reveal(draw, this.controlCard, playerContext); cardsToDiscard.add(draw); } @@ -2111,7 +2111,7 @@ private void harvest(Game game, MoveContext context, Player currentPlayer) { HashSet cardNames = new HashSet(); List cardToDiscard = new ArrayList(); for (int i = 0; i < 4; i++) { - Card draw = game.draw(context, controlCard, 4 - i); + Card draw = game.draw(context, Cards.harvest, 4 - i); if (draw == null) { break; } @@ -2158,12 +2158,12 @@ private void horseTradersDungeon(MoveContext context, Player currentPlayer) { private void jester(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); targetContext.attackedPlayer = targetPlayer; - Card draw = game.draw(targetContext, controlCard, 1); + Card draw = game.draw(targetContext, Cards.jester, 1); Card virtCard = draw; if (draw == null) @@ -2213,7 +2213,7 @@ private void huntingParty(Game game, MoveContext context, Player currentPlayer) ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(context, controlCard, -1)) != null && cardNames.contains(draw.getName())) { + while ((draw = game.draw(context, Cards.huntingParty, -1)) != null && cardNames.contains(draw.getName())) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -2238,7 +2238,7 @@ private void crossroads(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < victoryCards; i++) { - game.drawToHand(context, this.controlCard, victoryCards - i); + game.drawToHand(context, this, victoryCards - i); } int crossroadsPlayed = this.controlCard.numberTimesAlreadyPlayed; @@ -2261,7 +2261,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { context.actions += 2; } else if (option == TrustySteedOption.AddCards) { for (int i = 0; i < 2; i++) { - game.drawToHand(context, this.controlCard, 2 - i); + game.drawToHand(context, this, 2 - i); } } else if (option == TrustySteedOption.AddGold) { context.addCoins(2); @@ -2285,7 +2285,7 @@ private void trustySteed(Game game, MoveContext context, Player currentPlayer) { private void duchess(Game game, MoveContext context) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { MoveContext targetPlayerContext = new MoveContext(context, game, targetPlayer); - Card c = game.draw(targetPlayerContext, controlCard, 1); + Card c = game.draw(targetPlayerContext, Cards.duchess, 1); if(c != null) { boolean discard = (targetPlayer).controlPlayer.duchess_shouldDiscardCardFromTopOfDeck(targetPlayerContext, c); if(discard) { @@ -2318,8 +2318,8 @@ private void spiceMerchant(Game game, MoveContext context, Player currentPlayer) SpiceMerchantOption option = currentPlayer.controlPlayer.spiceMerchant_chooseOption(context); if(option == SpiceMerchantOption.AddCardsAndAction) { - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); context.actions += 1; } else { @@ -2353,7 +2353,7 @@ private void trader(MoveContext context, Player currentPlayer) { private void cartographer(Game game, MoveContext context, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 4; i++) { - Card card = game.draw(context, controlCard, 4 - i); + Card card = game.draw(context, Cards.cartographer, 4 - i); if (card != null) { topOfTheDeck.add(card); } @@ -2532,8 +2532,8 @@ private void steward(Game game, MoveContext context, Player currentPlayer) { if (option == Player.StewardOption.AddGold) { context.addCoins(2); } else if (option == Player.StewardOption.AddCards) { - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); } else if (option == Player.StewardOption.TrashCards) { CardList hand = currentPlayer.getHand(); if (hand.size() == 0) { @@ -2583,7 +2583,7 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { ArrayList trashed = new ArrayList(); for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); targetContext.attackedPlayer = targetPlayer; @@ -2591,7 +2591,7 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetContext, controlCard, 2 - i); + Card card = game.draw(targetContext, Cards.thief, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -2648,7 +2648,7 @@ private void thief(Game game, MoveContext context, Player currentPlayer) { private void militia(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -2753,7 +2753,7 @@ private void menagerie(Game game, MoveContext context, Player currentPlayer) { int numCards = distinct ? 3 : 1; for (int i = 0; i < numCards; i++) { - game.drawToHand(context, this.controlCard, numCards - i); + game.drawToHand(context, this, numCards - i); } } @@ -2925,7 +2925,7 @@ private void miningVillage(MoveContext context, Player currentPlayer) { private void minion(Game game, MoveContext context, Player currentPlayer) { ArrayList playersToAttack = new ArrayList(); for (Player player : game.getPlayersInTurnOrder()) { - if (player == currentPlayer || !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player == currentPlayer || !Util.isDefendedFromAttack(game, player, this)) { playersToAttack.add(player); if (player != currentPlayer) { player.attacked(this.controlCard, context); @@ -2951,10 +2951,10 @@ private void minion(Game game, MoveContext context, Player currentPlayer) { player.discard(player.hand.remove(0), this.controlCard, targetContext); } - game.drawToHand(targetContext, this.controlCard, 4); - game.drawToHand(targetContext, this.controlCard, 3); - game.drawToHand(targetContext, this.controlCard, 2); - game.drawToHand(targetContext, this.controlCard, 1); + game.drawToHand(targetContext, this, 4); + game.drawToHand(targetContext, this, 3); + game.drawToHand(targetContext, this, 2); + game.drawToHand(targetContext, this, 1); } } } @@ -2971,7 +2971,7 @@ private void pawn(Game game, MoveContext context, Player currentPlayer) { } else if (option == Player.PawnOption.AddBuy) { context.buys++; } else if (option == Player.PawnOption.AddCard) { - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 1); } else if (option == Player.PawnOption.AddGold) { context.addCoins(1); } @@ -2981,7 +2981,7 @@ private void pawn(Game game, MoveContext context, Player currentPlayer) { private void saboteur(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -2990,7 +2990,7 @@ private void saboteur(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw; - while ((draw = game.draw(playerContext, controlCard, -1)) != null) { + while ((draw = game.draw(playerContext, Cards.saboteur, -1)) != null) { if (draw.getCost(context) >= 3) { int value = draw.getCost(context); value -= 2; @@ -3039,8 +3039,8 @@ private void shantyTown(Game game, MoveContext context, Player currentPlayer) { } if (!actions) { - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); } } @@ -3082,14 +3082,14 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla // Note that this.controlCard is the opposite check of other attacks, the spy/scrying pool lets // the current player look at their own deck which is a good thing, so always // allow that - if (player == currentPlayer || (!Util.isDefendedFromAttack(game, player, this.controlCard))) { + if (player == currentPlayer || (!Util.isDefendedFromAttack(game, player, this))) { if (player != currentPlayer) { player.attacked(this.controlCard, context); } MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card card = game.draw(playerContext, controlCard, 1); + Card card = game.draw(playerContext, this, 1); if (card != null) { player.reveal(card, this.controlCard, playerContext); @@ -3116,7 +3116,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla ArrayList cardsToPutInHand = new ArrayList(); Card draw = null; - while ((draw = game.draw(context, controlCard, -1)) != null) { + while ((draw = game.draw(context, Cards.scryingPool, -1)) != null) { currentPlayer.reveal(draw, this.controlCard, new MoveContext(context, game, currentPlayer)); cardsToPutInHand.add(draw); if(!(draw.isAction(currentPlayer))) { @@ -3133,7 +3133,7 @@ private void spyAndScryingPool(Game game, MoveContext context, Player currentPla private void conspirator(Game game, MoveContext context, Player currentPlayer) { if (context.actionsPlayedSoFar >= 3) { context.actions++; - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 1); } } @@ -3149,7 +3149,7 @@ private void wishingWell(Game game, MoveContext context, Player currentPlayer) { if (!options.isEmpty()) { Card card = currentPlayer.controlPlayer.wishingWell_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(card, this.controlCard, context); - Card draw = game.draw(context, controlCard, 1); + Card draw = game.draw(context, Cards.wishingWell, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -3165,7 +3165,7 @@ private void wishingWell(Game game, MoveContext context, Player currentPlayer) { private void upgrade(MoveContext context, Player currentPlayer) { if (currentPlayer.getHand().size() > 0) { - Card card = currentPlayer.controlPlayer.upgrade_cardToTrash(context, Cards.upgrade, false); + Card card = currentPlayer.controlPlayer.upgrade_cardToTrash(context); if (card == null || !currentPlayer.hand.contains(card)) { Util.playerError(currentPlayer, "Upgrade trash error, upgrading a random card."); card = Util.randomCard(currentPlayer.hand); @@ -3176,7 +3176,7 @@ private void upgrade(MoveContext context, Player currentPlayer) { currentPlayer.hand.remove(card); currentPlayer.trash(card, this.controlCard, context); - card = currentPlayer.controlPlayer.upgrade_cardToObtain(context, Cards.upgrade, value, potion); + card = currentPlayer.controlPlayer.upgrade_cardToObtain(context, value, potion); if (card != null) { if (card.getCost(context) != value || card.costPotion() != potion) { Util.playerError(currentPlayer, "Upgrade error, new card does not cost value of the old card +1."); @@ -3200,7 +3200,7 @@ private void ironworks(Game game, MoveContext context, Player currentPlayer) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 1); } } } @@ -3214,9 +3214,9 @@ private void nobles(Game game, MoveContext context, Player currentPlayer) { if (option == Player.NoblesOption.AddActions) { context.actions += 2; } else if (option == Player.NoblesOption.AddCards) { - game.drawToHand(context, this.controlCard, 3); - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 3); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); } } } @@ -3225,8 +3225,8 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { Card[] revealedCards = new Card[2]; Player nextPlayer = game.getNextPlayer(); MoveContext targetContext = new MoveContext(game, nextPlayer); - revealedCards[0] = game.draw(targetContext, controlCard, 2); - revealedCards[1] = game.draw(targetContext, controlCard, 1); + revealedCards[0] = game.draw(targetContext, Cards.tribute, 2); + revealedCards[1] = game.draw(targetContext, Cards.tribute, 1); if (revealedCards[0] != null) { nextPlayer.reveal(revealedCards[0], this.controlCard, targetContext); @@ -3252,8 +3252,8 @@ private void tribute(Game game, MoveContext context, Player currentPlayer) { context.addCoins(2); } if (card instanceof VictoryCard) { - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); } } } @@ -3265,12 +3265,12 @@ private void copperSmith(MoveContext context) { private void swindler(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card draw = game.draw(playerContext, controlCard, 1); + Card draw = game.draw(playerContext, Cards.swindler, 1); if (draw != null) { player.trash(draw, this.controlCard, playerContext); @@ -3312,7 +3312,7 @@ private void swindler(Game game, MoveContext context, Player currentPlayer) { private void goons(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -3363,7 +3363,7 @@ private void youngwitch(Game game, MoveContext context, Player currentPlayer) { } for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !isDefendedFromAttack(game, targetPlayer, this)) { if (targetPlayer.hand.contains(game.baneCard) && game.pileSize(Cards.curse) > 0 && targetPlayer.revealBane(context)) { targetPlayer.reveal(game.baneCard, this.controlCard, new MoveContext(game, targetPlayer)); } else { @@ -3380,7 +3380,7 @@ private void followers(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.estate, this.controlCard, context); for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -3414,7 +3414,7 @@ private void stables(Game game, MoveContext context, Player currentPlayer) { context.actions++; for (int i = 0; i < 3; i++) { - if(!game.drawToHand(context, this.controlCard, 3 - i)) { + if(!game.drawToHand(context, this, 3 - i)) { break; } } @@ -3424,7 +3424,7 @@ private void stables(Game game, MoveContext context, Player currentPlayer) { private void margrave(Game game, MoveContext context, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -3441,13 +3441,13 @@ private void margrave(Game game, MoveContext context, Player currentPlayer) { private void oracle(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer == currentPlayer || !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer == currentPlayer || !Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); targetContext.attackedPlayer = targetPlayer; ArrayList cards = new ArrayList(); for(int i=0; i < 2; i++) { - Card c = game.draw(targetContext, controlCard, 2 - i); + Card c = game.draw(targetContext, Cards.oracle, 2 - i); if(c == null) { break; } @@ -3496,7 +3496,7 @@ private void oracle(Game game, MoveContext context, Player currentPlayer) { } for(int i=0; i < 2; i++) { - game.drawToHand(context, this.controlCard, 2 - i); + game.drawToHand(context, this, 2 - i); } } @@ -3517,7 +3517,7 @@ private void oasis(MoveContext context, Player currentPlayer) { private void jackOfAllTrades(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.silver, this.controlCard, context); - Card c = game.draw(context, controlCard, 1); + Card c = game.draw(context, Cards.jackOfAllTrades, 1); if(c != null) { boolean discard = currentPlayer.controlPlayer.jackOfAllTrades_shouldDiscardCardFromTopOfDeck(context, c); if(discard) { @@ -3529,7 +3529,7 @@ private void jackOfAllTrades(Game game, MoveContext context, Player currentPlaye int cardsToDraw = 5 - currentPlayer.hand.size(); for (int i = 0; i < cardsToDraw; ++i) { - if(!game.drawToHand(context, this.controlCard, cardsToDraw - i)) { + if(!game.drawToHand(context, this, cardsToDraw - i)) { break; } } @@ -3678,7 +3678,7 @@ private void cellar(Game game, MoveContext context, Player currentPlayer) { } for (int i = 0; i < numberOfCards; ++i) { - game.drawToHand(context, this.controlCard, numberOfCards - i); + game.drawToHand(context, this, numberOfCards - i); } } } @@ -3706,7 +3706,7 @@ private void bureaucrat(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainNewCard(Cards.silver, this, context); for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -3754,7 +3754,7 @@ private void golem(Game game, MoveContext context, Player currentPlayer) { ArrayList toOrder = new ArrayList(); while (toOrder.size() < 2) { - Card draw = game.draw(context, controlCard, -1); + Card draw = game.draw(context, Cards.golem, -1); if (draw == null) { break; } @@ -3815,7 +3815,7 @@ private void adventurer(Game game, MoveContext context, Player currentPlayer) { int treasureCardsRevealed = 0; while (treasureCardsRevealed < 2) { - Card draw = game.draw(context, controlCard, -1); + Card draw = game.draw(context, Cards.adventurer, -1); if (draw == null) { break; } @@ -3840,7 +3840,7 @@ private void library(Game game, MoveContext context, Player currentPlayer) { // we need to manually remove the minus one card token currentPlayer.setMinusOneCardToken(false, context); while (currentPlayer.hand.size() < 7) { - Card draw = game.draw(context, controlCard, -1); + Card draw = game.draw(context, Cards.library, -1); if (draw == null) { break; } @@ -3905,7 +3905,7 @@ private void haven(MoveContext context, Player currentPlayer) { private void pirateShip(Game game, MoveContext context, Player currentPlayer) { ArrayList playersToAttack = new ArrayList(); for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { playersToAttack.add(targetPlayer); targetPlayer.attacked(this.controlCard, context); } @@ -3922,7 +3922,7 @@ private void pirateShip(Game game, MoveContext context, Player currentPlayer) { List cardToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetContext, controlCard, 2 - i); + Card card = game.draw(targetContext, Cards.pirateShip, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4013,12 +4013,12 @@ private void feast(MoveContext context, Player currentPlayer) { private void chancellor(Game game, MoveContext context, Player currentPlayer) { if (currentPlayer.getDeckSize() == 0) return; - boolean discard = currentPlayer.controlPlayer.chancellor_shouldDiscardDeck(context, this.controlCard); + boolean discard = currentPlayer.controlPlayer.chancellor_shouldDiscardDeck(context); if (discard) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, Cards.chancellor, 0), this.controlCard, null, false, false); } } } @@ -4142,7 +4142,7 @@ protected void addToHand(Player player, Card card) { } protected Card draw(MoveContext context, int cardsLeftToDraw) { - return context.game.draw(context, controlCard, cardsLeftToDraw); + return context.game.draw(context, this, cardsLeftToDraw); } protected Player[] getAllPlayers() { @@ -4225,7 +4225,7 @@ public void nobleBrigandAttack(MoveContext moveContext, boolean defensible) { int i = 0; for (Player targetPlayer : context.game.getPlayersInTurnOrder()) { // Hinterlands card details in the rules states that noble brigand is not defensible when triggered from a buy - if (targetPlayer != player && (!defensible || !Util.isDefendedFromAttack(context.game, targetPlayer, this.controlCard))) { + if (targetPlayer != player && (!defensible || !Util.isDefendedFromAttack(context.game, targetPlayer, this))) { targetPlayer.attacked(this.controlCard, moveContext); MoveContext targetContext = new MoveContext(context.game, targetPlayer); targetContext.attackedPlayer = targetPlayer; @@ -4234,7 +4234,7 @@ public void nobleBrigandAttack(MoveContext moveContext, boolean defensible) { List cardsToDiscard = new ArrayList(); for (int j = 0; j < 2; j++) { - Card card = context.game.draw(targetContext, controlCard, 2 - j); + Card card = context.game.draw(targetContext, Cards.nobleBrigand, 2 - j); if(card == null) { break; } @@ -4327,7 +4327,7 @@ private void sage(Game game, MoveContext context, Player currentPlayer) { ArrayList toDiscard = new ArrayList(); Card draw = null; - while ((draw = game.draw(context, controlCard, -1)) != null && draw.getCost(context) < 3) { + while ((draw = game.draw(context, Cards.sage, -1)) != null && draw.getCost(context) < 3) { currentPlayer.reveal(draw, this.controlCard, context); toDiscard.add(draw); } @@ -4436,7 +4436,7 @@ public void beggar(Player currentPlayer, MoveContext context) { public void catacombs(Game game, Player currentPlayer, MoveContext context) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = game.draw(context, controlCard, 3 - i); + Card card = game.draw(context, Cards.catacombs, 3 - i); if (card != null) { topOfTheDeck.add(card); } @@ -4447,9 +4447,9 @@ public void catacombs(Game game, Player currentPlayer, MoveContext context) { while (!topOfTheDeck.isEmpty()) { currentPlayer.discard(topOfTheDeck.remove(0), this.controlCard, context); } - game.drawToHand(context, this.controlCard, 3); - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 3); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); } else { // Put the cards in hand for (Card c : topOfTheDeck) { @@ -4631,7 +4631,7 @@ private void graverobber(Game game, Player currentPlayer, MoveContext context) { } private void ironmonger(Game game, Player currentPlayer, MoveContext context) { - Card card = game.draw(context, controlCard, 1); + Card card = game.draw(context, Cards.ironmonger, 1); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -4648,7 +4648,7 @@ private void ironmonger(Game game, Player currentPlayer, MoveContext context) { context.addCoins(1); } if (card instanceof VictoryCard) { - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 1); } } } @@ -4677,7 +4677,7 @@ private void mystic(Game game, MoveContext context, Player currentPlayer) { if (options.size() > 0) { Card toName = currentPlayer.controlPlayer.mystic_cardGuess(context, options); currentPlayer.controlPlayer.namedCard(toName, this.controlCard, context); - Card draw = game.draw(context, controlCard, 1); + Card draw = game.draw(context, Cards.mystic, 1); if (draw != null) { currentPlayer.reveal(draw, this.controlCard, context); @@ -4703,7 +4703,7 @@ private void scavenger(Game game, MoveContext context, Player currentPlayer) game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, Cards.scavenger, 0), this.controlCard, null, false, false); } } @@ -4743,7 +4743,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { } for (int i = 0; i < numberOfCards; ++i) { - game.drawToHand(context, this.controlCard, numberOfCards - i); + game.drawToHand(context, this, numberOfCards - i); } } @@ -4775,7 +4775,7 @@ private void storeroom(Game game, MoveContext context, Player currentPlayer) { private void wanderingMinstrel(Player currentPlayer, MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 3; i++) { - Card card = context.game.draw(context, controlCard, 3 - i); + Card card = context.game.draw(context, Cards.wanderingMinstrel, 3 - i); if (card == null) { break; } @@ -4814,7 +4814,7 @@ private void rebuild(Player currentPlayer, MoveContext context) { Card last = null; // search for first Victory card that was not named - while ((last = context.game.draw(context, controlCard, -1)) != null) { + while ((last = context.game.draw(context, Cards.rebuild, -1)) != null) { if (last instanceof VictoryCard && !last.equals(named)) break; cards.add(last); currentPlayer.reveal(last, this.controlCard, context); @@ -4856,7 +4856,7 @@ private void rogue(Game game, MoveContext context, Player currentPlayer) { currentPlayer.gainCardAlreadyInPlay(toGain, this.controlCard, context); } else { // Other players trash a card for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(game, targetPlayer); targetContext.attackedPlayer = targetPlayer; @@ -4864,7 +4864,7 @@ private void rogue(Game game, MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(targetContext, controlCard, 2 - i); + Card card = game.draw(targetContext, Cards.rogue, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -4916,7 +4916,7 @@ private void pillage(Game game, MoveContext context, Player currentPlayer) for (Player targetPlayer : game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer && - !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard) && + !Util.isDefendedFromAttack(game, targetPlayer, this) && targetPlayer.getHand().size() >= 5) { targetPlayer.attacked(this.controlCard, context); @@ -4952,12 +4952,12 @@ private void governor(Game game, MoveContext context, Player currentPlayer) { Util.playerError(currentPlayer, "Governor option error, ignoring."); } else { if (option == Player.GovernorOption.AddCards) { - game.drawToHand(context, this.controlCard, 3); - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 3); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); for (Player player : getAllPlayers()) { if (player != context.getPlayer()) { - game.drawToHand(new MoveContext(game, player), this.controlCard, 1); + game.drawToHand(new MoveContext(game, player), this, 1); } } } else if (option == Player.GovernorOption.GainTreasure) { @@ -5025,7 +5025,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { ArrayList cards = new ArrayList(); Player nextPlayer = game.getNextPlayer(); for (int i = 0; i < 5; i++) { - Card card = game.draw(context, controlCard, 5 - i); + Card card = game.draw(context, Cards.envoy, 5 - i); if (card != null) { cards.add(card); currentPlayer.reveal(card, this.controlCard, context); @@ -5064,7 +5064,7 @@ private void envoy(Game game, MoveContext context, Player currentPlayer) { public void isTrashed(MoveContext context) { switch (this.controlCard.behaveAsCard().getType()) { case Rats: - context.game.drawToHand(context, this.controlCard, 1, true); + context.game.drawToHand(context, this, 1, true); break; case Squire: // Need to ensure that there is at least one Attack card that can be gained, @@ -5138,9 +5138,9 @@ else if (gainEstates) context.player.hand.add(this.controlCard); break; case Cultist: - context.game.drawToHand(context, this.controlCard, 3, false); - context.game.drawToHand(context, this.controlCard, 2, false); - context.game.drawToHand(context, this.controlCard, 1, false); + context.game.drawToHand(context, this, 3, false); + context.game.drawToHand(context, this, 2, false); + context.game.drawToHand(context, this, 1, false); break; case SirVander: context.player.controlPlayer.gainNewCard(Cards.gold, this.controlCard, context); @@ -5170,7 +5170,7 @@ public void isGained(MoveContext context) { private void survivors(MoveContext context, Game game, Player currentPlayer) { ArrayList topOfTheDeck = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = game.draw(context, controlCard, 2 - i); + Card card = game.draw(context, Cards.survivors, 2 - i); if (card != null) { topOfTheDeck.add(card); } @@ -5222,7 +5222,7 @@ private void survivors(MoveContext context, Game game, Player currentPlayer) { private void cultist(MoveContext context, Game game, Player currentPlayer) { for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -5244,7 +5244,7 @@ private void cultist(MoveContext context, Game game, Player currentPlayer) { private void urchin(MoveContext context, Game game, Player currentPlayer) { for (Player player : context.game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -5287,13 +5287,13 @@ private void mercenary(MoveContext context, Game game, Player currentPlayer) if (cardsTrashedCount == 2) { - game.drawToHand(context, this.controlCard, 2); - game.drawToHand(context, this.controlCard, 1); + game.drawToHand(context, this, 2); + game.drawToHand(context, this, 1); context.addCoins(2); for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -5314,7 +5314,7 @@ private void marauder(MoveContext context, Game game, Player currentPlayer) for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !isDefendedFromAttack(game, player, this.controlCard)) + if (player != currentPlayer && !isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); @@ -5388,14 +5388,14 @@ private void madman(MoveContext context, Game game, Player currentPlayer) { int handSize = currentPlayer.hand.size(); for (int i = 0; i < handSize; ++i) { - game.drawToHand(context, this.controlCard, handSize - i); + game.drawToHand(context, this, handSize - i); } } } private void vagrant(MoveContext context, Game game, Player currentPlayer) { - Card c = game.draw(context, controlCard, 1); + Card c = game.draw(context, Cards.vagrant, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c.getType() == Cards.Type.Curse || c.isShelter() || (c instanceof VictoryCard) || (c.isRuins(currentPlayer))) { @@ -5408,7 +5408,7 @@ private void vagrant(MoveContext context, Game game, Player currentPlayer) private void knight(MoveContext context, Player currentPlayer) { for (Player targetPlayer : context.game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(context.game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(context.game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); MoveContext targetContext = new MoveContext(context.game, targetPlayer); targetContext.attackedPlayer = targetPlayer; @@ -5416,7 +5416,7 @@ private void knight(MoveContext context, Player currentPlayer) { List cardsToDiscard = new ArrayList(); for (int i = 0; i < 2; i++) { - Card card = context.game.draw(targetContext, controlCard, 2 - i); + Card card = context.game.draw(targetContext, this, 2 - i); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); @@ -5490,7 +5490,7 @@ private void dameAnna(MoveContext context, Player currentPlayer) { private void sirMichael(MoveContext context, Game game, Player currentPlayer) { for (Player player : context.game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -5580,7 +5580,7 @@ private void soothsayer(Game game, MoveContext context, Player currentPlayer) for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); @@ -5590,7 +5590,7 @@ private void soothsayer(Game game, MoveContext context, Player currentPlayer) if (curseGained.equals(Cards.curse)) { - game.drawToHand(playerContext, this.controlCard, 1); + game.drawToHand(playerContext, this, 1); } } } @@ -5612,7 +5612,7 @@ private void taxman(Game game, MoveContext context, Player currentPlayer) for (Player player : game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this.controlCard)) + if (player != currentPlayer && !Util.isDefendedFromAttack(game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); @@ -5698,7 +5698,7 @@ private void advisor(Game game, MoveContext context, Player currentPlayer) for (int i = 0; i < 3; ++i) { - Card card = game.draw(context, controlCard, 3 - i); + Card card = game.draw(context, Cards.advisor, 3 - i); if (card != null) { @@ -5813,7 +5813,7 @@ private void journeyman(Game game, MoveContext context, Player currentPlayer) { int diffCardsFound = 0; // search for the first 3 cards that were not named - while (diffCardsFound < 3 && (last = context.game.draw(context, controlCard, -1)) != null) { + while (diffCardsFound < 3 && (last = context.game.draw(context, Cards.journeyman, -1)) != null) { if (!last.equals(named)) { ++diffCardsFound; cardsToKeep.add(last); @@ -5919,7 +5919,7 @@ private void doctor(Game game, MoveContext context, Player currentPlayer) { ArrayList revealedCards = new ArrayList(); for (int i = 0; i < 3; ++i) { - Card card = game.draw(context, controlCard, 3 - i); + Card card = game.draw(context, Cards.doctor, 3 - i); if (card != null) { currentPlayer.reveal(card, this.controlCard, context); @@ -5972,7 +5972,7 @@ public void doctorOverpay(MoveContext context) private void herald(Game game, MoveContext context, Player currentPlayer) { - Card draw = game.draw(context, controlCard, 1); + Card draw = game.draw(context, Cards.herald, 1); if (draw != null) { @@ -6089,7 +6089,7 @@ private void artificer(Game game, MoveContext context, Player currentPlayer) { private void bridgeTroll(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { MoveContext targetContext = new MoveContext(context.game, targetPlayer); targetContext.attackedPlayer = targetPlayer; targetPlayer.attacked(this.controlCard, context); @@ -6151,7 +6151,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) { ArrayList playersToAttack = new ArrayList(); for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != currentPlayer && !Util.isDefendedFromAttack(game, targetPlayer, this)) { playersToAttack.add(targetPlayer); } } @@ -6163,7 +6163,7 @@ private void giant(Game game, MoveContext context, Player currentPlayer) MoveContext targetContext = new MoveContext(game, targetPlayer); targetContext.attackedPlayer = targetPlayer; - Card card = game.draw(targetContext, controlCard, 1); + Card card = game.draw(targetContext, Cards.giant, 1); if (card != null) { targetPlayer.reveal(card, this.controlCard, targetContext); int cardCost = card.getCost(context); @@ -6209,7 +6209,7 @@ private void hero(Game game, MoveContext context, Player currentPlayer) private void magpie(Game game, MoveContext context, Player currentPlayer) { - Card c = game.draw(context, controlCard, 1); + Card c = game.draw(context, Cards.magpie, 1); if (c != null) { currentPlayer.reveal(c, this.controlCard, context); if (c instanceof TreasureCard) { @@ -6226,12 +6226,12 @@ private void magpie(Game game, MoveContext context, Player currentPlayer) private void messenger(Game game, MoveContext context, Player currentPlayer) { if (currentPlayer.getDeckSize() == 0) return; - boolean discard = currentPlayer.controlPlayer.messenger_shouldDiscardDeck(context, this); + boolean discard = currentPlayer.controlPlayer.messenger_shouldDiscardDeck(context); if (discard) { GameEvent event = new GameEvent(GameEvent.Type.DeckPutIntoDiscardPile, (MoveContext) context); game.broadcastEvent(event); while (currentPlayer.getDeckSize() > 0) { - currentPlayer.discard(game.draw(context, controlCard, 0), this.controlCard, null, false, false); + currentPlayer.discard(game.draw(context, Cards.messenger, 0), this.controlCard, null, false, false); } } } @@ -6258,7 +6258,7 @@ private void miser(Game game, MoveContext context, Player currentPlayer) { private void ranger(Game game, MoveContext context, Player currentPlayer) { if(currentPlayer.flipJourneyToken(context)) { - drawToHand(context, this.controlCard, 5); + drawToHand(context, this, 5); } } @@ -6284,13 +6284,13 @@ private void raze(Game game, MoveContext context, Player currentPlayer) { if (trashCost == 0) return; else if (trashCost == 1) { - Card c = game.draw(context, controlCard, 1); + Card c = game.draw(context, Cards.raze, 1); if (c != null) currentPlayer.hand.add(c); } else { ArrayList lookAtCards = new ArrayList(trashCost); for (int i = 0; i < trashCost; ++i) { - Card c = game.draw(context, controlCard, trashCost - i); + Card c = game.draw(context, Cards.raze, trashCost - i); if (c == null) break; lookAtCards.add(c); @@ -6311,7 +6311,7 @@ else if (trashCost == 1) { private void soldier(Game game, MoveContext context, Player currentPlayer) { context.addCoins(context.countAttackCardsInPlayThisTurn() - 1); //without this soldier for (Player player : context.game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this)) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; @@ -6338,14 +6338,14 @@ private void storyteller(Game game, MoveContext context, Player currentPlayer) { context.spendCoins(coins); for (int i = 0; i < coins; i++) { - game.drawToHand(context, this.controlCard, coins - i); + game.drawToHand(context, this, coins - i); } } private void swampHagHauntedWoods(Game game, MoveContext context, Player currentPlayer) { for (Player targetPlayer : context.game.getPlayersInTurnOrder()) { if (targetPlayer != currentPlayer) { - if (!Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (!Util.isDefendedFromAttack(game, targetPlayer, this)) { targetPlayer.attacked(this.controlCard, context); currentPlayer.addDurationEffectOnOtherPlayer(targetPlayer, this.type); } @@ -6362,7 +6362,7 @@ private void treasureHunter(Game game, MoveContext context, Player currentPlayer private void warrior(Game game, MoveContext context, Player currentPlayer) { ArrayList attackedPlayers = new ArrayList(); for (Player player : context.game.getPlayersInTurnOrder()) { - if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this.controlCard)) { + if (player != currentPlayer && !Util.isDefendedFromAttack(context.game, player, this)) { attackedPlayers.add(player); } } @@ -6372,7 +6372,7 @@ private void warrior(Game game, MoveContext context, Player currentPlayer) { player.attacked(this.controlCard, context); MoveContext playerContext = new MoveContext(game, player); playerContext.attackedPlayer = player; - Card draw = game.draw(playerContext, controlCard, numTravellers - i); + Card draw = game.draw(playerContext, Cards.warrior, numTravellers - i); if (draw != null) { int cost = draw.getCost(context); if (draw.costPotion()) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 0c8e073a6..70ea9bddb 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -614,7 +614,7 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { } @Override - public boolean chancellor_shouldDiscardDeck(MoveContext context, Card responsible) { + public boolean chancellor_shouldDiscardDeck(MoveContext context) { return true; } @@ -971,12 +971,12 @@ public Card wishingWell_cardGuess(MoveContext context, ArrayList cardList) } @Override - public Card upgrade_cardToTrash(MoveContext context, Card responsible, boolean passable) { + public Card upgrade_cardToTrash(MoveContext context) { if (context.getPlayer().getHand().size() == 0) { return null; } - if (context.getPlayer().getHand().size() == 1 && !passable) { + if (context.getPlayer().getHand().size() == 1) { return context.getPlayer().getHand().get(0); } @@ -996,15 +996,15 @@ public Card upgrade_cardToTrash(MoveContext context, Card responsible, boolean p } } - if (card == null && !passable) { + if (card == null) { card = lowestCard(context, context.getPlayer().getHand(), false); } return card; } - + @Override - public Card upgrade_cardToObtain(MoveContext context, Card responsible, int exactCost, boolean potion) { + public Card upgrade_cardToObtain(MoveContext context, int exactCost, boolean potion) { return bestCardInPlay(context, exactCost, true, potion, true); } @@ -2636,12 +2636,32 @@ public GovernorOption governor_chooseOption(MoveContext context) { @Override public Card governor_cardToTrash(MoveContext context) { - return controlPlayer.upgrade_cardToTrash(context, Cards.governor, true); + if (context.getPlayer().getHand().size() == 0) { + return null; + } + + Card card = pickOutCard(context.getPlayer().getHand(), getTrashCards()); + if (card != null) { + return card; + } + for (Card c : context.getPlayer().getHand()) { + if(c instanceof VictoryCard) { + continue; + } + + for(Card avail : context.getCardsInGame()) { + if(Cards.isSupplyCard(avail) && avail.getCost(context) == c.getCost(context) + 1 && context.getCardsLeftInPile(avail) > 0 && !avail.costPotion()) { + return c; + } + } + } + + return card; } @Override public Card governor_cardToObtain(MoveContext context, int exactCost, boolean potion) { - return controlPlayer.upgrade_cardToObtain(context, Cards.governor, exactCost, potion); + return bestCardInPlay(context, exactCost, true, potion, true); } @Override @@ -3409,7 +3429,7 @@ public Card messenger_cardToObtain(MoveContext context) { return bestCardInPlay(context, 4, true); } - public boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible) { + public boolean messenger_shouldDiscardDeck(MoveContext context) { return true; } diff --git a/vdom/src/com/vdom/core/EventCardImpl.java b/vdom/src/com/vdom/core/EventCardImpl.java index 3f27c40fb..7728e86bb 100644 --- a/vdom/src/com/vdom/core/EventCardImpl.java +++ b/vdom/src/com/vdom/core/EventCardImpl.java @@ -376,7 +376,7 @@ private void save(MoveContext context) { private void scoutingParty(MoveContext context) { ArrayList cards = new ArrayList(); for (int i = 0; i < 5; i++) { - Card card = context.game.draw(context, controlCard, 5 - i); + Card card = context.game.draw(context, Cards.scoutingParty, 5 - i); if (card != null) { cards.add(card); } diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 5cc0214d2..2453955df 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -2740,7 +2740,7 @@ public void gameEvent(GameEvent event) { player.deck.add(c); } } - player.shuffleDeck(context, event.card); + player.shuffleDeck(context, Cards.inn); } else if (gainedCardAbility.equals(Cards.borderVillage)) { boolean validCard = false; int gainedCardCost = event.card.getCost(context); @@ -2791,7 +2791,7 @@ public void gameEvent(GameEvent event) { } else if (gainedCardAbility.equals(Cards.lostCity)) { for(Player targetPlayer : getPlayersInTurnOrder()) { if(targetPlayer != player) { - drawToHand(new MoveContext(Game.this, targetPlayer), event.card, 1, true); + drawToHand(new MoveContext(Game.this, targetPlayer), Cards.lostCity, 1, true); } } } diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index 0698269b7..e02bd9c32 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -374,11 +374,11 @@ public Card[] militia_attack_cardsToKeep(MoveContext context) { } @Override - public boolean chancellor_shouldDiscardDeck(MoveContext context, Card responsible) { - if(context.isQuickPlay() && shouldAutoPlay_chancellor_shouldDiscardDeck(context, responsible)) { - return super.chancellor_shouldDiscardDeck(context, responsible); + public boolean chancellor_shouldDiscardDeck(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_chancellor_shouldDiscardDeck(context)) { + return super.chancellor_shouldDiscardDeck(context); } - return selectBoolean(context, responsible); + return selectBoolean(context, Cards.chancellor); } @Override @@ -660,27 +660,23 @@ public Card wishingWell_cardGuess(MoveContext context, ArrayList cardList) } @Override - public Card upgrade_cardToTrash(MoveContext context, Card responsible, boolean passable) { - if(context.isQuickPlay() && shouldAutoPlay_upgrade_cardToTrash(context, passable)) { - return super.upgrade_cardToTrash(context, responsible, passable); + public Card upgrade_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_upgrade_cardToTrash(context)) { + return super.upgrade_cardToTrash(context); } SelectCardOptions sco = new SelectCardOptions().setPickType(PickType.TRASH) - .setActionType(ActionType.TRASH).setCardResponsible(responsible); - if(passable) /*For governor where you MAY trash a card*/ - { - sco = sco.setPassable(); - } + .setActionType(ActionType.TRASH).setCardResponsible(Cards.upgrade); return getCardFromHand(context, sco); } @Override - public Card upgrade_cardToObtain(MoveContext context, Card responsible, int exactCost, boolean potion) { + public Card upgrade_cardToObtain(MoveContext context, int exactCost, boolean potion) { if(context.isQuickPlay() && shouldAutoPlay_upgrade_cardToObtain(context, exactCost, potion)) { - return super.upgrade_cardToObtain(context, responsible, exactCost, potion); + return super.upgrade_cardToObtain(context, exactCost, potion); } SelectCardOptions sco = new SelectCardOptions().exactCost(exactCost) .potionCost(potion ? 1 : 0).setActionType(ActionType.GAIN) - .setCardResponsible(responsible); + .setCardResponsible(Cards.upgrade); return getFromTable(context, sco); } @@ -2075,7 +2071,7 @@ public Card mystic_cardGuess(MoveContext context, ArrayList cardList) { @Override public boolean scavenger_shouldDiscardDeck(MoveContext context) { - if(context.isQuickPlay() && shouldAutoPlay_chancellor_shouldDiscardDeck(context, Cards.scavenger)) { + if(context.isQuickPlay() && shouldAutoPlay_scavenger_shouldDiscardDeck(context)) { return super.scavenger_shouldDiscardDeck(context); } return selectBoolean(context, Cards.scavenger); @@ -2220,6 +2216,27 @@ public GovernorOption governor_chooseOption(MoveContext context) { GovernorOption[] options = GovernorOption.values(); return options[selectOption(context, Cards.governor, options)]; } + + @Override + public Card governor_cardToTrash(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_governor_cardToTrash(context)) { + return super.governor_cardToTrash(context); + } + SelectCardOptions sco = new SelectCardOptions().setPickType(PickType.TRASH) + .setPassable().setActionType(ActionType.TRASH).setCardResponsible(Cards.governor); + return getCardFromHand(context, sco); + } + + @Override + public Card governor_cardToObtain(MoveContext context, int exactCost, boolean potion) { + if(context.isQuickPlay() && shouldAutoPlay_governor_cardToObtain(context, exactCost, potion)) { + return super.governor_cardToObtain(context, exactCost, potion); + } + SelectCardOptions sco = new SelectCardOptions().exactCost(exactCost) + .potionCost(potion ? 1 : 0).setActionType(ActionType.GAIN) + .setCardResponsible(Cards.governor); + return getFromTable(context, sco); + } @Override public Card envoy_cardToDiscard(MoveContext context, Card[] cards) { @@ -2742,12 +2759,11 @@ public TreasureCard hero_treasureToObtain(MoveContext context) { } @Override - public boolean messenger_shouldDiscardDeck(MoveContext context, - Card responsible) { - if(context.isQuickPlay() && shouldAutoPlay_messenger_shouldDiscardDeck(context, responsible)) { - return super.messenger_shouldDiscardDeck(context, responsible); + public boolean messenger_shouldDiscardDeck(MoveContext context) { + if(context.isQuickPlay() && shouldAutoPlay_messenger_shouldDiscardDeck(context)) { + return super.messenger_shouldDiscardDeck(context); } - return selectBoolean(context, responsible); + return selectBoolean(context, Cards.messenger); } @Override diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index d02a3a810..6fb53dc1e 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1438,7 +1438,7 @@ public ArrayList getActionsInHand(Player player) { public abstract TreasureCard[] thief_treasuresToGain(MoveContext context, TreasureCard[] treasures); - public abstract boolean chancellor_shouldDiscardDeck(MoveContext context, Card responsible); + public abstract boolean chancellor_shouldDiscardDeck(MoveContext context); public abstract TreasureCard mine_treasureFromHandToUpgrade(MoveContext context); @@ -1496,9 +1496,9 @@ public ArrayList getActionsInHand(Player player) { public abstract Card wishingWell_cardGuess(MoveContext context, ArrayList cardList); - public abstract Card upgrade_cardToTrash(MoveContext context, Card responsible, boolean passable); + public abstract Card upgrade_cardToTrash(MoveContext context); - public abstract Card upgrade_cardToObtain(MoveContext context, Card responsible, int exactCost, boolean potion); + public abstract Card upgrade_cardToObtain(MoveContext context, int exactCost, boolean potion); public abstract MinionOption minion_chooseOption(MoveContext context); @@ -1844,7 +1844,7 @@ public ArrayList getActionsInHand(Player player) { public abstract TreasureCard hero_treasureToObtain(MoveContext context); public abstract boolean traveller_shouldExchange(MoveContext context, Card traveller, Card exchange); public abstract Card messenger_cardToObtain(MoveContext context); - public abstract boolean messenger_shouldDiscardDeck(MoveContext context, Card responsible); + public abstract boolean messenger_shouldDiscardDeck(MoveContext context); public abstract boolean miser_shouldTakeTreasure(MoveContext context); public abstract Card ratcatcher_cardToTrash(MoveContext context); public abstract boolean raze_shouldTrashRazePlayed(MoveContext context); diff --git a/vdom/src/com/vdom/core/QuickPlayPlayer.java b/vdom/src/com/vdom/core/QuickPlayPlayer.java index 881ab72b6..67039122e 100644 --- a/vdom/src/com/vdom/core/QuickPlayPlayer.java +++ b/vdom/src/com/vdom/core/QuickPlayPlayer.java @@ -84,7 +84,7 @@ public boolean shouldAutoPlay_militia_attack_cardsToKeep(MoveContext context) { return false; } - public boolean shouldAutoPlay_chancellor_shouldDiscardDeck(MoveContext context, Card responsible) { + public boolean shouldAutoPlay_chancellor_shouldDiscardDeck(MoveContext context) { return true; } @@ -220,8 +220,11 @@ public boolean shouldAutoPlay_wishingWell_cardGuess(MoveContext context) { return true; } + public boolean shouldAutoPlay_scavenger_shouldDiscardDeck(MoveContext context) { + return false; + } - public boolean shouldAutoPlay_upgrade_cardToTrash(MoveContext context, boolean passable) { + public boolean shouldAutoPlay_upgrade_cardToTrash(MoveContext context) { return false; } @@ -776,6 +779,14 @@ public boolean shouldAutoPlay_selectPutBackOption(MoveContext context, List playersToAttack = new ArrayList(); for (Player targetPlayer : game.getPlayersInTurnOrder()) { - if (targetPlayer != player && !Util.isDefendedFromAttack(game, targetPlayer, this.controlCard)) { + if (targetPlayer != player && !Util.isDefendedFromAttack(game, targetPlayer, this)) { playersToAttack.add(targetPlayer); } } From d9fdd04a41432b2ed5e132ac0bc50ad108b62fbb Mon Sep 17 00:00:00 2001 From: dominionator Date: Thu, 28 Jan 2016 22:24:01 -0700 Subject: [PATCH 071/141] Inheritance: Exchange ability for inherited traveller. --- vdom/src/com/vdom/core/Player.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vdom/src/com/vdom/core/Player.java b/vdom/src/com/vdom/core/Player.java index 6fb53dc1e..260ad2036 100644 --- a/vdom/src/com/vdom/core/Player.java +++ b/vdom/src/com/vdom/core/Player.java @@ -1006,18 +1006,18 @@ public void discard(Card card, Card responsible, MoveContext context) { private Card traveller_exchange(MoveContext context, Card card) { Card exchange = null; - if (card.equals(Cards.peasant)) exchange = Cards.soldier; + if (card.behaveAsCard().equals(Cards.peasant)) exchange = Cards.soldier; if (card.equals(Cards.soldier)) exchange = Cards.fugitive; if (card.equals(Cards.fugitive)) exchange = Cards.disciple; if (card.equals(Cards.disciple)) exchange = Cards.teacher; - if (card.equals(Cards.page)) exchange = Cards.treasureHunter; + if (card.behaveAsCard().equals(Cards.page)) exchange = Cards.treasureHunter; if (card.equals(Cards.treasureHunter)) exchange = Cards.warrior; if (card.equals(Cards.warrior)) exchange = Cards.hero; if (card.equals(Cards.hero)) exchange = Cards.champion; if (context.getCardsLeftInPile(exchange) <= 0) exchange = null; if (exchange != null) { - if(!controlPlayer.traveller_shouldExchange(context, card, exchange)) + if(!controlPlayer.traveller_shouldExchange(context, card.behaveAsCard(), exchange)) exchange = null; } return exchange; From 5e030be3a59cee323590fd234a55b9779b6fe46c Mon Sep 17 00:00:00 2001 From: dominionator Date: Fri, 29 Jan 2016 00:15:01 -0700 Subject: [PATCH 072/141] Inheritance: Adding inherited "when Attack played" abilities --- vdom/src/com/vdom/core/BasePlayer.java | 54 ++++++++--------- vdom/src/com/vdom/core/Game.java | 2 +- vdom/src/com/vdom/core/IndirectPlayer.java | 18 +++--- vdom/src/com/vdom/core/Util.java | 67 ++++++++++------------ 4 files changed, 67 insertions(+), 74 deletions(-) diff --git a/vdom/src/com/vdom/core/BasePlayer.java b/vdom/src/com/vdom/core/BasePlayer.java index 70ea9bddb..f8d1e0f52 100644 --- a/vdom/src/com/vdom/core/BasePlayer.java +++ b/vdom/src/com/vdom/core/BasePlayer.java @@ -82,29 +82,14 @@ public Card[] actionCardsToPlayInOrder(MoveContext context) { @Override public Card getAttackReaction(MoveContext context, Card responsible, boolean defended, Card lastCard) { - Card[] reactionCards = getReactionCards(defended); + Card[] reactionCards = getAttackReactionCards(defended); for (Card c : reactionCards) { - if (!c.equals(Cards.marketSquare) && !c.equals(Cards.watchTower)) + if (!reactedSet.contains(c)) { - if ( c.equals(Cards.secretChamber) - || c.equals(Cards.horseTraders) - || c.equals(Cards.beggar) - || c.equals(Cards.caravanGuard) - || c.equals(Cards.moat) - ) - { - if (!reactedSet.contains(c)) - { - reactedSet.add(c); - return c; - } - } - else - { - return c; - } - } + reactedSet.add(c); + return c; + } } return null; } @@ -451,23 +436,25 @@ public Card[] getEasyWhenTrashCards() { return EASY_WHEN_TRASH_CARDS; } - protected Card[] getReactionCards(boolean defended) { + protected Card[] getAttackReactionCards(boolean defended) { ArrayList reactionCards = new ArrayList(); boolean moatSelected = false; boolean secretChamberSelected = false; for (Card c : getHand()) { - if (c.equals(Cards.moat) && !defended && !moatSelected) { + Card a = c; + if (c.equals(Cards.estate) && isAttackReaction(getInheritance())) { + a = getInheritance(); + } + if (a.equals(Cards.moat) && !defended && !moatSelected) { reactionCards.add(c); moatSelected = true; - } else if (c.equals(Cards.secretChamber) && !secretChamberSelected) { + } else if (a.equals(Cards.secretChamber) && !secretChamberSelected) { reactionCards.add(c); secretChamberSelected = true; - } else if ( c.equals(Cards.horseTraders) - || c.equals(Cards.watchTower) - || c.equals(Cards.beggar) - || c.equals(Cards.marketSquare) - || c.equals(Cards.caravanGuard) + } else if ( a.equals(Cards.horseTraders) + || a.equals(Cards.beggar) + || a.equals(Cards.caravanGuard) ) { reactionCards.add(c); } @@ -475,7 +462,16 @@ protected Card[] getReactionCards(boolean defended) { return reactionCards.toArray(new Card[0]); } - protected boolean containsCardCostingAtLeast(MoveContext context, Iterable toSearch, Card[] toLookFor, int cost) { + protected boolean isAttackReaction(Card c) { + return c != null && ( + c.equals(Cards.moat) + || c.equals(Cards.secretChamber) + || c.equals(Cards.horseTraders) + || c.equals(Cards.beggar) + || c.equals(Cards.caravanGuard)); + } + + protected boolean containsCardCostingAtLeast(MoveContext context, Iterable toSearch, Card[] toLookFor, int cost) { for(Card c : toSearch) { for(Card checkCard : toLookFor) { if(checkCard.equals(c) && (c.getCost(context) >= cost)) { diff --git a/vdom/src/com/vdom/core/Game.java b/vdom/src/com/vdom/core/Game.java index 2453955df..04d54c409 100644 --- a/vdom/src/com/vdom/core/Game.java +++ b/vdom/src/com/vdom/core/Game.java @@ -939,7 +939,7 @@ protected void playerBeginTurn(Player player, MoveContext context) { e.printStackTrace(); } context.freeActionInEffect--; - } else if(card.equals(Cards.horseTraders)) { + } else if(card.behaveAsCard().equals(Cards.horseTraders)) { Card horseTrader = player.horseTraders.remove(0); player.hand.add(horseTrader); drawToHand(context, horseTrader, 1); diff --git a/vdom/src/com/vdom/core/IndirectPlayer.java b/vdom/src/com/vdom/core/IndirectPlayer.java index e02bd9c32..25b74701b 100644 --- a/vdom/src/com/vdom/core/IndirectPlayer.java +++ b/vdom/src/com/vdom/core/IndirectPlayer.java @@ -1800,20 +1800,22 @@ public Card[] margrave_attack_cardsToKeep(MoveContext context) { @Override public Card getAttackReaction(MoveContext context, Card responsible, boolean defended, Card lastCard) { ArrayList reactionCards = new ArrayList(); - for (Card c : getReactionCards(defended)) { - if (!c.equals(Cards.marketSquare) && !c.equals(Cards.watchTower)) { - reactionCards.add(c); - } + for (Card c : getAttackReactionCards(defended)) { + reactionCards.add(c); } if (reactionCards.size() > 0) { ArrayList cards = new ArrayList(); for (Card c : reactionCards) { + Card a = c; + if (c.equals(Cards.estate)) { + a = getInheritance(); + } if (lastCard == null || !Game.suppressRedundantReactions - || c.getName() != lastCard.getName() - || c.equals(Cards.horseTraders) - || c.equals(Cards.beggar) - || c.equals(Cards.caravanGuard) + || a.getName() != lastCard.getName() + || a.equals(Cards.horseTraders) + || a.equals(Cards.beggar) + || a.equals(Cards.caravanGuard) ) { cards.add(c); } diff --git a/vdom/src/com/vdom/core/Util.java b/vdom/src/com/vdom/core/Util.java index d165b54ac..cbe70ff8a 100644 --- a/vdom/src/com/vdom/core/Util.java +++ b/vdom/src/com/vdom/core/Util.java @@ -271,20 +271,28 @@ static boolean isDefendedFromAttack(Game game, Player player, Card responsible) } Card reactionCard = null; - while ((reactionCard = player.controlPlayer.getAttackReaction(context, responsible, defended, reactionCard)) != null) { + Card reactionCardAbility = null; + while ((reactionCard = player.controlPlayer.getAttackReaction(context, responsible, defended, reactionCardAbility)) != null) { + //TODO: error check reactionCard + GameEvent event = new GameEvent(GameEvent.Type.CardRevealed, context); event.card = reactionCard; game.broadcastEvent(event); - if (reactionCard.equals(Cards.secretChamber)) - doSecretChamber(context, game, player, responsible); - else if (reactionCard.equals(Cards.horseTraders)) - doHorseTraders(context, game, player, responsible); - else if (reactionCard.equals(Cards.beggar)) - doBeggar(context, game, player, responsible); - else if (reactionCard.equals(Cards.caravanGuard)) - doCaravanGuard(context, game, player, responsible); - else if (reactionCard.equals(Cards.moat)) { + reactionCardAbility = reactionCard; + if (reactionCard.equals(Cards.estate)) { + reactionCardAbility = player.getInheritance(); + } + + if (reactionCardAbility.equals(Cards.secretChamber)) + doSecretChamber(context, game, player, responsible, reactionCard); + else if (reactionCardAbility.equals(Cards.horseTraders)) + doHorseTraders(context, game, player, responsible, reactionCard); + else if (reactionCardAbility.equals(Cards.beggar)) + doBeggar(context, game, player, responsible, reactionCard); + else if (reactionCardAbility.equals(Cards.caravanGuard)) + doCaravanGuard(context, game, player, responsible, reactionCard); + else if (reactionCardAbility.equals(Cards.moat)) { defended = true; event = new GameEvent(GameEvent.Type.PlayerDefended, context); @@ -296,23 +304,16 @@ else if (reactionCard.equals(Cards.moat)) { return defended; } - static boolean doSecretChamber(MoveContext context, Game game, Player player, Card responsible) { + private static boolean doSecretChamber(MoveContext context, Game game, Player player, Card responsible, Card reactionCard) { boolean found = false; for (Card card : player.hand) { - if (card.equals(Cards.secretChamber)) { + if (card.equals(reactionCard)) { found = true; } } if (found) { -// GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, context); -// event.card = Cards.secretChamber; -// game.broadcastEvent(event); -// -// event = new GameEvent(GameEvent.Type.CardRevealed, context); -// event.card = Cards.secretChamber; -// game.broadcastEvent(event); game.drawToHand(context, Cards.secretChamber, 2); game.drawToHand(context, Cards.secretChamber, 1); @@ -354,38 +355,32 @@ static boolean doSecretChamber(MoveContext context, Game game, Player player, Ca return found; } - static boolean doHorseTraders(MoveContext context, Game game, Player player, Card responsible) { + private static boolean doHorseTraders(MoveContext context, Game game, Player player, Card responsible, Card reactionCard) { Card horseTraders = null; for (Card card : player.hand) { - if (card.equals(Cards.horseTraders)) { + if (card.equals(reactionCard)) { horseTraders = card; + if (reactionCard.equals(Cards.estate)) { + ((CardImpl)card).startInheritingCardAbilities(Cards.horseTraders.getTemplateCard().instantiate()); + } } } if (horseTraders != null) { -// GameEvent event = new GameEvent(GameEvent.Type.PlayingAction, context); -// event.card = Cards.horseTraders; -// game.broadcastEvent(event); -// -// event = new GameEvent(GameEvent.Type.CardRevealed, context); -// event.card = Cards.horseTraders; -// game.broadcastEvent(event); - player.hand.remove(horseTraders); player.horseTraders.add(horseTraders); - return true; } return false; } - static boolean doBeggar(MoveContext context, Game game, Player player, Card responsible) { + private static boolean doBeggar(MoveContext context, Game game, Player player, Card responsible, Card reactionCard) { Card beggar = null; for (Card card : player.hand) { - if (card.equals(Cards.beggar)) { + if (card.equals(reactionCard)) { beggar = card; } } @@ -404,11 +399,11 @@ static boolean doBeggar(MoveContext context, Game game, Player player, Card resp return false; } - static boolean doCaravanGuard(MoveContext context, Game game, Player player, Card responsible) { - ActionCardImpl caravanGuard = null; + private static boolean doCaravanGuard(MoveContext context, Game game, Player player, Card responsible, Card reactionCard) { + Card caravanGuard = null; for (Card card : player.hand) { - if (card.equals(Cards.caravanGuard)) { - caravanGuard = (ActionCardImpl) card; + if (card.equals(reactionCard)) { + caravanGuard = card; } } From ef34a652f0bb637016717429aad62c060e0ce525 Mon Sep 17 00:00:00 2001 From: dominionator Date: Fri, 29 Jan 2016 21:16:37 -0700 Subject: [PATCH 073/141] Bug fixes/enhancements Fixing Teacher to allow UI to place tokens on empty piles. Fixing so card callable at start of turn can be intersperced with other "simple" start of turn effects. Fixing missing string on Disciple. Changing Duration Attacks to have text more distinct. --- androminion/res/values/card_styles.xml | 5 ++--- androminion/res/values/strings-cards.xml | 2 +- vdom/src/com/vdom/core/Game.java | 5 +++++ vdom/src/com/vdom/core/IndirectPlayer.java | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/androminion/res/values/card_styles.xml b/androminion/res/values/card_styles.xml index 233c5116b..1450cc0be 100644 --- a/androminion/res/values/card_styles.xml +++ b/androminion/res/values/card_styles.xml @@ -39,9 +39,8 @@