From 3349f974f1eb07d7f7b4fa2798a7e9efeac0e528 Mon Sep 17 00:00:00 2001 From: "jean.chalard" Date: Sat, 22 Aug 2009 05:59:43 +0000 Subject: [PATCH] J : * New interface. * This breaks a lot of things. It is not feature-equivalent. It probably doesn't compile under windows and doesn't work on PSP. * Damage is not resolved any more. This will have to be fixed. * Blockers can't be ordered any more. This will have to be fixed. * A lot of new art is included. --- projects/mtg/Makefile | 2 +- projects/mtg/bin/Res/graphics/BattleIcon.png | Bin 0 -> 1892 bytes .../mtg/bin/Res/graphics/DefenderIcon.png | Bin 0 -> 1798 bytes projects/mtg/bin/Res/graphics/gold.png | Bin 0 -> 8913 bytes projects/mtg/bin/Res/graphics/goldglow.png | Bin 0 -> 4515 bytes projects/mtg/bin/Res/graphics/handback.png | Bin 0 -> 26209 bytes projects/mtg/bin/Res/graphics/mana.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/manablack.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/manablue.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/managreen.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/manared.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/manawhite.psi | Bin 128 -> 128 bytes projects/mtg/bin/Res/graphics/menuside2.png | Bin 0 -> 446 bytes projects/mtg/bin/Res/graphics/phasebar.png | Bin 25434 -> 23196 bytes projects/mtg/bin/Res/graphics/shadow.png | Bin 0 -> 101 bytes projects/mtg/bin/Res/graphics/shop.jpg | Bin 21281 -> 42606 bytes projects/mtg/bin/Res/graphics/simon_pink.png | Bin 0 -> 2438 bytes projects/mtg/bin/Res/graphics/wood.png | Bin 0 -> 12577 bytes projects/mtg/bin/Res/sets/black.jpg | Bin 0 -> 10881 bytes projects/mtg/bin/Res/sets/black_thumb.jpg | Bin 0 -> 885 bytes projects/mtg/bin/Res/sets/blue.jpg | Bin 0 -> 11875 bytes projects/mtg/bin/Res/sets/blue_thumb.jpg | Bin 0 -> 1063 bytes projects/mtg/bin/Res/sets/green.jpg | Bin 0 -> 11770 bytes projects/mtg/bin/Res/sets/green_thumb.jpg | Bin 0 -> 901 bytes projects/mtg/bin/Res/sets/red.jpg | Bin 0 -> 13032 bytes projects/mtg/bin/Res/sets/red_thumb.jpg | Bin 0 -> 1019 bytes projects/mtg/bin/Res/sets/white.jpg | Bin 0 -> 9591 bytes projects/mtg/bin/Res/sets/white_thumb.jpg | Bin 0 -> 830 bytes projects/mtg/include/AIMomirPlayer.h | 34 +- projects/mtg/include/AIPlayer.h | 6 +- projects/mtg/include/ActionLayer.h | 4 +- projects/mtg/include/ActionStack.h | 12 +- projects/mtg/include/AllAbilities.h | 18 +- projects/mtg/include/CardDisplay.h | 6 +- projects/mtg/include/CardGui.h | 49 +- projects/mtg/include/Damage.h | 10 +- projects/mtg/include/DamageResolverLayer.h | 4 +- projects/mtg/include/DamagerDamaged.h | 11 +- projects/mtg/include/DuelLayers.h | 35 +- projects/mtg/include/GameApp.h | 2 +- projects/mtg/include/GameObserver.h | 8 +- projects/mtg/include/GameOptions.h | 58 +- projects/mtg/include/GameStateDeckViewer.h | 17 +- projects/mtg/include/GuiCardsController.h | 2 +- projects/mtg/include/GuiLayers.h | 28 +- projects/mtg/include/GuiPhaseBar.h | 4 +- projects/mtg/include/MTGCard.h | 51 +- projects/mtg/include/MTGCardInstance.h | 5 +- projects/mtg/include/MTGDeck.h | 6 - projects/mtg/include/MTGGameZones.h | 43 +- projects/mtg/include/MTGGuiHand.h | 5 +- projects/mtg/include/MTGGuiPlay.h | 5 +- projects/mtg/include/PhaseRing.h | 2 +- projects/mtg/include/PlayGuiObject.h | 59 +- .../mtg/include/PlayGuiObjectController.h | 2 +- projects/mtg/include/Player.h | 6 +- projects/mtg/include/TargetChooser.h | 30 +- projects/mtg/include/Targetable.h | 2 +- projects/mtg/include/TexturesCache.h | 3 +- projects/mtg/include/WEvent.h | 196 +-- projects/mtg/include/config.h | 7 + projects/mtg/src/AIMomirPlayer.cpp | 2 +- projects/mtg/src/AIPlayer.cpp | 1529 +++++++++-------- projects/mtg/src/ActionLayer.cpp | 14 +- projects/mtg/src/ActionStack.cpp | 65 +- projects/mtg/src/Blocker.cpp | 12 +- projects/mtg/src/CardDisplay.cpp | 18 +- projects/mtg/src/CardGui.cpp | 458 +++-- projects/mtg/src/Credits.cpp | 50 +- projects/mtg/src/Damage.cpp | 13 +- projects/mtg/src/DamageResolverLayer.cpp | 80 +- projects/mtg/src/DamagerDamaged.cpp | 8 +- projects/mtg/src/DuelLayers.cpp | 161 +- projects/mtg/src/GameApp.cpp | 73 +- projects/mtg/src/GameObserver.cpp | 86 +- projects/mtg/src/GameOptions.cpp | 40 +- projects/mtg/src/GameStateDuel.cpp | 38 +- projects/mtg/src/GameStateMenu.cpp | 85 +- projects/mtg/src/GameStateOptions.cpp | 21 +- projects/mtg/src/GameStateShop.cpp | 11 +- projects/mtg/src/GuiLayers.cpp | 80 +- projects/mtg/src/GuiPhaseBar.cpp | 19 +- projects/mtg/src/MTGAbility.cpp | 140 +- projects/mtg/src/MTGCard.cpp | 123 +- projects/mtg/src/MTGCardInstance.cpp | 59 +- projects/mtg/src/MTGDeck.cpp | 2 +- projects/mtg/src/MTGGameZones.cpp | 32 +- projects/mtg/src/MTGGuiHand.cpp | 10 +- projects/mtg/src/MTGGuiPlay.cpp | 71 +- projects/mtg/src/MTGRules.cpp | 83 +- projects/mtg/src/OptionItem.cpp | 8 +- projects/mtg/src/PlayGuiObject.cpp | 158 +- projects/mtg/src/PlayGuiObjectController.cpp | 2 + projects/mtg/src/Player.cpp | 8 +- projects/mtg/src/ReplacementEffects.cpp | 152 +- projects/mtg/src/ShopItem.cpp | 82 +- projects/mtg/src/TargetChooser.cpp | 139 +- projects/mtg/src/TestSuiteAI.cpp | 16 +- projects/mtg/src/TexturesCache.cpp | 14 +- projects/mtg/src/Token.cpp | 28 +- projects/mtg/src/WEvent.cpp | 63 +- 101 files changed, 2424 insertions(+), 2361 deletions(-) create mode 100644 projects/mtg/bin/Res/graphics/BattleIcon.png create mode 100644 projects/mtg/bin/Res/graphics/DefenderIcon.png create mode 100644 projects/mtg/bin/Res/graphics/gold.png create mode 100644 projects/mtg/bin/Res/graphics/goldglow.png create mode 100644 projects/mtg/bin/Res/graphics/handback.png create mode 100644 projects/mtg/bin/Res/graphics/menuside2.png create mode 100644 projects/mtg/bin/Res/graphics/shadow.png create mode 100644 projects/mtg/bin/Res/graphics/simon_pink.png create mode 100644 projects/mtg/bin/Res/graphics/wood.png create mode 100644 projects/mtg/bin/Res/sets/black.jpg create mode 100644 projects/mtg/bin/Res/sets/black_thumb.jpg create mode 100644 projects/mtg/bin/Res/sets/blue.jpg create mode 100644 projects/mtg/bin/Res/sets/blue_thumb.jpg create mode 100644 projects/mtg/bin/Res/sets/green.jpg create mode 100644 projects/mtg/bin/Res/sets/green_thumb.jpg create mode 100644 projects/mtg/bin/Res/sets/red.jpg create mode 100644 projects/mtg/bin/Res/sets/red_thumb.jpg create mode 100644 projects/mtg/bin/Res/sets/white.jpg create mode 100644 projects/mtg/bin/Res/sets/white_thumb.jpg diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index 3d3d56f25..970b07f3c 100644 --- a/projects/mtg/Makefile +++ b/projects/mtg/Makefile @@ -1,4 +1,4 @@ -OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/Blocker.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/ConstraintResolver.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DamageResolverLayer.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiCardsController.o objs/GuiLayers.o objs/GuiPhaseBar.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGGuiHand.o objs/MTGGuiPlay.o objs/MTGRules.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/PriceList.o objs/ReplacementEffects.o objs/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/TexturesCache.o objs/Token.o objs/Translate.o objs/utils.o objs/WEvent.o +OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/Blocker.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardSelector.o objs/ConstraintResolver.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DamageResolverLayer.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGGuiHand.o objs/MTGGuiPlay.o objs/MTGRules.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/Pos.o objs/PriceList.o objs/ReplacementEffects.o objs/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/TexturesCache.o objs/Token.o objs/Translate.o objs/utils.o objs/WEvent.o DEPS = $(patsubst objs/%.o, deps/%.d, $(OBJS)) RESULT = $(shell psp-config --psp-prefix 2> Makefile.cache) diff --git a/projects/mtg/bin/Res/graphics/BattleIcon.png b/projects/mtg/bin/Res/graphics/BattleIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..00e10971f96453d4bba297cae508ffccdbe0b29e GIT binary patch literal 1892 zcmV-q2b=hbP)P000>X1^@s6#OZ}&00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXV+ z2P88`RuWtQ000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000KRNklHG^3|)5=4;?`mSEfCogl&PD(pC9UHnL*1e6k(On?$%Utd)?`t9B2Yt@*c z3|)_OeL8mgR4AN2X_#CA0LBs`lHLf#Y7FD3iy*2}R#w~zZW+IMJ3Z}-t<`mXUemM&!TCVjiWM@YtS^y2v-QEI z2rSO(4CEUxl;Z!4CQ8Y^LkHGB`{ZL47#WG+?cIk}CDL@}_ z{I^MGQ8ycER9DVCy`QTw6ZhdCQN3Sx>4GTyX4sRp^&2A5k&6jADmi++#sSw~oz%cln z64CdM+)yh%@q{l32)y+3jrh~6&F>!mZjGnRW&3_QtsCWvycipid!OSh7zT@Y zeenyQ^oNFR1w{w9?brc#BX>>rPthyyMxc5V81K~4tMaj=!|~&|+x>zmOL2?E0!`B( z=d*Dz=IF0pSN%kOUfz8JgM;O{03iezV_=NICb^zzysI3kI=$#QHjL1uhELB6T;}Xz!dbc}RI)-Nk_3yz0(k)<%QEEon*e}8zu&)8 zRn=3qH8smMO%sZukOfHFu7}#+|H-e~>`KUw;hqQ*VFH$v(SIU=E9ta1>MDCep+d7- zEO!7XrJ1LHW>JIF@p!!bvzs^Ju5<&0^qHpFc;Kmhum9pV-?9gNDR|D$g3~-OEi!0>GV`5BN9;;f=5tF2b+v8Kk&+uI*(8E9>5 z#Pw@I1f~=uQv_NPxY#*`2{mFyii-9`Q?VPl$t6iz1Y{3Q<+w=*0nT~A>-8QEg=S%Q zIM8{rA8AuUb4xwc7{`aFhA^(oYXQ!_qiXS<+zyrk0DyB2Ic>euNeepY_3KvR`p_jT zE2)6PX2BbOJPnVhA4(+hw~(HGMrY}eB}W5ElJ2NJo6j%|P@2eGvH;FGc5b=XGdDJg zs$vCAn=8@z-Uqnk=|wb|crl=c_oUN_P_~0yK(>pe_NT(YqE!Ll>tDG?ofsd^oAUb5 zbzvGTas{<@UxvM~2)aQYkFY2PgnI?Dp-CZmdo8U%zY< zLZH&^Mq$aS7vK4K;ORgx#Eu;O3n?$JNIcx$_B%IMtcqkHtxX#` zE{$BHoO9IF+=Za3|Nfk3=$BbxB}u}Ye?Ip5eOtF!H#XFtA%v{?UjV}}psFfNGmVzI z1f1*^WB|DA`B$mkZbyA(6+Rr9ygEA{etzk^qtWPdC(oSAf2j3=rxS_fG2hHgs}RD> zHBCC5hNfvK`;vs_nj{>`3@(i!1F=~wXsE8m(SP;mD0j`Gh=(vR09?8X1Ovc?Sb)6z zTI6xNmAvh+5!hrvmN_IMKm=b{^BjzEa4x`w00Cr5;HDH~Hd%*F1`;|DoCiiHfaz&K ei2{KIo&F6zmwi~&L*Kjr0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXV+ z2PQLhU~t|5000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000JINkl-YSghj@$=XR4ceNSe^ZC2dNml7gt%8&Saq!6q9dHY`|J z0FYK;y=Q~D z<3P_8j_bM~1DKwi{&S;VJGr{H#>(o-qLgx?zkeHE*2T|e7q<@$@9cEiekSXogk<6J zrLbD7=CszdVxNEBeF9}mymI0u&i`Y7;)PG45nMz)VJJvr5N?!vn#GMUWZ^7%YUDHfJT>A6@&ew_W(YxPR`ti7I&FUP>JQo6Ea4LH{DGL0lZzbMeus&1g^&_t27r8bH^YO2zg9{e48xEx3~?L> zW6Vc27~e7e&2pt8=e{5C#_Jg}QZU+chy7y#!f5>50G-+0X6sU`-TFved^`HI%zsqOej)46m>j>AwT0@d( zqEvBfv5jd2ynOgBM#V@W$mep*JT)cv?%MOkcDvoF*XyU^IQ}od%+&OsMuvw6=jH?Y zdV8q_7a8B_;<_H~wd*u0>ntuTa^w0IwMI%%O*k+SGteDjtVJL=FgeZXubyW1(2=g8 zfuS==lI)d_tjXRzyH5=^zQd2c_bSWF_vrOkNaGG#hom~Dx>+aEmaJ=;*(cf7=b|(m z*wrNN)QQrVVxgaz?w_$|e4Kr|c55l+k_0lvV)5Zy759^Umsd) zWHy`qgAklf(vVtZ3!@c{W{p*Ogmaf6HG)PMv%J94W#!#=-sA-8y2G5l!t@!*)FH^16Sy^B0 z>FVlw7!ks9aC;ReO_EZ((K?W%F*4)OXf}!Cgd|Bw(iG3nVXeg)LlP%EdTeB~4;@#? z=eT+21{QfWjw4*xMF_)*>5#r=87GROp^ab@-*IrV9&sFDtwm{#H5MTSS{dRb!B~UL zxL^&&XjBT7YLz&S?%iBme9`kfMz&>mZmLaJWtI2ufK#v64;gJ}h7IzC9+c83rO-yB zjllv4z(OXIAxRRnN^xBWgoCz*l~QT8(CwFxe=`WiT6qdlvZXh$3; zWc~DQrBo?NlYE*aQ%2ioEEa@#$5<0fBc@!}sr#O9ja7|iySX;hpSg1Cs1xiTZ!qL8 z^T7x3{uL;#!;%H@%WsV$q${hfjL}Nc3>BR)nK4>j!& olR_zg+e@+!$JKT7F;1C3p9ZA4A8WdHyG07*qoM6N<$f~g~G3jhEB literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/graphics/gold.png b/projects/mtg/bin/Res/graphics/gold.png new file mode 100644 index 0000000000000000000000000000000000000000..bf09620ebfe8cd9cd35c3ce11e6c3fa7fc358f3a GIT binary patch literal 8913 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 literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/graphics/goldglow.png b/projects/mtg/bin/Res/graphics/goldglow.png new file mode 100644 index 0000000000000000000000000000000000000000..765da4755dd8dee50f4692eb1180817707784e91 GIT binary patch literal 4515 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 Bq1gZc literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/graphics/handback.png b/projects/mtg/bin/Res/graphics/handback.png new file mode 100644 index 0000000000000000000000000000000000000000..3dada1cb596dfee975989cf3e75d45b8fe54c49b GIT binary patch literal 26209 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 QDF6Tf07*qoM6N<$f}8X&`2YX_ literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/graphics/mana.psi b/projects/mtg/bin/Res/graphics/mana.psi index 6c14812a9e3b9be83bdb8ea260ca256322609945..34a5ab2f6619fa2be44dac19ef0e6a8ca1e9df06 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A#Zy$TT)c&%Guf1hovMoqmk&L@N0LWPz-2eap delta 87 zcmZo*Y+&?fU|?bJWMlw>hW)nZKijq?O4x&VxA{*xfM|m*CHp59d=3uhKkqNNZFZny k-g1YC(5oQ+K8N$g`}1xuv%9_RsonBSDZ7S5iHZJ(0Ivoh<^TWy diff --git a/projects/mtg/bin/Res/graphics/manablack.psi b/projects/mtg/bin/Res/graphics/manablack.psi index 61db33ea100b9e24b0cf648815b79ba5e8aac1b8..6d192146d75e673b24d3882e646fa3176483622c 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A#hW)nZKijq?O4x&VxA{*xfM|m*CHp59d=3uhKkqNNZFZny k-g1YC(5oQ+K8N$g`}1xuv%9_RsonBSDZ7S5iHZJ(0Ivoh<^TWy diff --git a/projects/mtg/bin/Res/graphics/manablue.psi b/projects/mtg/bin/Res/graphics/manablue.psi index 5e0beeaeac4760ac25090d1e52e6e8a8b3c3a859..e4f1afc695d9ee54a9a95b9a8b7d3078c2c9f80b 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A#P*#O6ueaW^Ubwx7n_5ecI7K{J@ delta 87 zcmZo*Y+&?fU|?bJWMlw>hW)nZKijq?O4x&VxA{*xfM|m*CHp59d=3uhKkqNNZFZny k-g1YC(5oQ+K8N$g`}1xuv%9_RsonBSDZ7S5iHZJ(0Ivoh<^TWy diff --git a/projects/mtg/bin/Res/graphics/managreen.psi b/projects/mtg/bin/Res/graphics/managreen.psi index 48522d41786cfc5652c4c77259356867a5963616..441bbe060118ac2764a08bef4bb54ac78889933e 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A##AazAD?)CspL>IOI delta 87 zcmZo*Y+&?fU|?bJWMlw>hW)nZKijq?O4x&VxA{*xfM|m*CHp59d=3uhKkqNNZFZny k-g1YC(5oQ+K8N$g`}1xuv%9_RsonBSDZ7S5iHZJ(0Ivoh<^TWy diff --git a/projects/mtg/bin/Res/graphics/manared.psi b/projects/mtg/bin/Res/graphics/manared.psi index f85f6f4343b0be9882b5e58adf4ab238fa391673..aa3af43012d56de51770425d517fba774917a776 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A#hW)nZKijq?O4x&VxA{*xfM|m*CHp59d=3uhKkqNNZFZny k-g1YC(5oQ+K8N$g`}1xuv%9_RsonBSDZ7S5iHZJ(0Ivoh<^TWy diff --git a/projects/mtg/bin/Res/graphics/manawhite.psi b/projects/mtg/bin/Res/graphics/manawhite.psi index 600d6a58b306a0afc29fd306244f81c0a169a0ea..9fbe3e47160be0b4c16ca605f7b33179301e6663 100644 GIT binary patch literal 128 zcmZQ#U|}d?0D*@6roNNy_rKq559UG%uItJ+AdD=A#n+qNZ2*n@bt`A<54XoD^#`zIEB4i4u(?=QG*cA#S3a)*e} zt04Y9hx5hz^KLJ*yS?qH-SSK+yM{!G10X#haC=*>z3us8d)?DUcA7vl{_M-QkG)=M S4^(Gw*_Uh!Qd1=3ZVv!DM=kFF diff --git a/projects/mtg/bin/Res/graphics/menuside2.png b/projects/mtg/bin/Res/graphics/menuside2.png new file mode 100644 index 0000000000000000000000000000000000000000..6f69197600f49058dcc9f03df028b5712fa6e85a GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^$v~XK!3HEJ+4boHDVB6cUq=Rpjs4tz5?O(Ki4xa{ zlHmNblJdl&REB`W%)AmkKi3e2GGjes1BVuO0R{%fKu;IPkczms*EjMWQ4n!)TybXU zZj%X}oHF|o{C2U~+`4-{=KSuq_{ZEe690Ph4IE4q{G1OqER@p!tRT7YYzyP!%a@m) zox*c+LQk}ksSDIcb#^dF zkSLuk2obhcp2uV=%3gG^jS_l!1+B>XW&GL_55&hgZwiyJPZ!*BZbGVDNPHb6Mw<&;$T=)0v|H literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/graphics/phasebar.png b/projects/mtg/bin/Res/graphics/phasebar.png index cc3797de27619adac7d9b0f0a64cb34969b813f3..a11640e0c8475d71495e2c6ed89b2aca22565f55 100644 GIT binary patch literal 23196 zcmV+DKo`G>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXV~ z0}2kK_TLcz03ZNKL_t(|+U&h|n4MR3@Bi8Rt*6hKKBF?KRTTef9vzy{-rDaM$3 zaex#O2qeD*a&Hn!9P-OeBaj9m1e+KLC4d3j*v2-N<)UKAsvdRCj5Ph6GpE08-#-Ie6dCdPVnBwc7i>lfefgj-eKE4;=dp@2U;JM)YFa8OF z7k}B!Ls&wx1zI~=(3A7GG&aq>ClZO>yZWZD4NnGo9`lvO^t=Gi@o}60rwon@UKLX* zkOHKHpa2mKlC9A83d`Bh0eB7EKNVHJrceTuuPT`SiK zE|_^pNeJl`-JZAG^O&zBrdYmob{$k90Etqv@;3qywQtt`^WrZD1x%TxDU{`c+3?ym zkeoe>k~e!(TU*m-FTd@l51tP6JmxEpsgxj4U|BXxmo6ujN|P@X$mO!QP8r|xkQA|G zj^^+yFK45jW$|pdY851Bby5yyZ)$68`s|hOy#HmvG(<(WOXkd6&cB#HOPR$2r9k0G zi6$f(k_H7~Kfv&OJQa|YlCV-pAt(U5q~v)$Aa6S)<9Qa(Id8Y;F<&`Mv258gb;|z~ zVoLX4shSt#BZNRoiNvKnF~qw0IWAugZg`1WFu&{0^|$@(-%tMiv%#$IenCJ`-QHd< zOik0!G!3BY348dy|FUAfoO0IYEC>QxTU+_km;RCMyZ3Xnr;qK=ZQ=OQ!;FsfPk6?& z#nhxgN`dEBNbZ7#G2Z*uE;3n{=XR&q(>=!Ea2eMN>iVt8DU?HNe3B2l$te9HP!>d;-`^XVQp@0wqO-eK= zF@->S9{4`O^H6}O+E2mvc|r*OOVikAS(GCYTwABPDb2ctc`je^tG!l!nV3RUPNM(a z<$S4_;?hemoe^kl;RHcIxm@P$AO0;CTyOz*{qAoQR2QmJiila{!nwz}{YoIQoaUB! zcW$`jr(YZYS>rKRFJHi$ueqEH=C)!8kE2Hq@#xdf@$()1l$>C~GhBAjV&3)UYw1Xu zJpatYeDS+aa&XW;W6Y`K6hdH{CZ=g3grHn5Q!Ey79EWnbjOTf0CFe|Zd-8<3u6s@} zYsBYy9`onV=WAcTht1peaNuwcn>IemkpnM~Nev)`sN%Q*791HDxpbO zHSYxPzPf-DTB{Z=ns@!$TfSF6O4Kl4w|Xugy5m+XQ!=oBBW_`YhPF;Zy32Qe^b_uW zTE`3}kW#XKL5$zI<2qsu2}%PyFy$yedg5t5_4PF2a2VS%W`ucqk3b-V;19p_AN<|# z-HE1Y+_B~&8ZW+>FaFEFQY;qvRfWjvp;8OpHkz zfKovvHZBE$?^4K*(cj<0!NY^(3YE?COm%zmywy%5%U7)6i(mRDw(Z=<;lq7weBv<< zAKXWJ_&A1PpzAt92z=jvNpem$q!j$dhc4h<@0iEly(zx+ox}X}XT8L9o!`A|fYwDR z9{$@XPl*uGwk)^2W(XQCQcIT1zy6Z9e1A&J70XsImPymw*GErp4^m1R8=J691KTv| zY;B`Z$fKDSo{;R={v4@v3ez;PZF^c98oA*H6+d(cF+7aOWaxHXdWGO3pxL%5luA4T ztkE=@fhUxrK`Abl5}_0WLBMw4TT*h^FeunIZY0E#B^loH`XWwva@}@?1r5zDY(F|M zW6y6qVf-rE?R4XoFEul`Lu1pwoIpx>PUIXvR;^mb>QzgaH@Asx&+TLL)_wH%k5o=^ zn#A{CJQ=(11d+<7fvz z-rPV(Q&!|0@h3;O{(sHmKW|Zs!R@QVl!m)`^80tO_1XLAKJ+XH_WYQ!>|x%1O_WO( z7U=KqCkO&A4?cY90$j7W`ubndEgH zO}zh_Ybg3JhNkZNjoT4IU>F98L}JEro;*Hu=Q~l2i|LlD=<9kvqZj@zxl2Dye*LFO zt^5Roi#|kZ;rl6dUQ0;JlS-v>e&^Q~@`1N6<_jM`$eKHP89I=|RKqODWav3+@Z%>Fv@~SJ zSeZXLvSo5iAp}>y<|=M@!yEYfzxo>F=uYs%O^GRWD}`YFf(~w5HHY8+ z?ce5a|MqWLyLRo22>)E!tznw{;)y4@_gmlL-@kqj|NixRxci=axaXd4@Qr)F%|nko zMtAqYb85F!%2g69x~z${Z<$rG?Q>+eix$n}qrdY3KKtq4VaeiFzV+<~x$h@W(%(N) zcT_(9(RX55#yMXrGm`rZG3A*M{A+K2FR`wrbhdS}VAdR#&h291>^T&r#d|*WCzQ($ zx~`K*Bv4B7+>s>P4~6Jxi(a9mcE^O!OQIjmG}!g@_ZZA)C}|}IwlvFB(l8`(47`j~|+H9d41(ZFja*Qq%W`sFjNt&kB$vqK`(isV}Dr9g``UE#E zUQBOO6W{&M|D;qZ)#G5b@u`3OX65(J0JE;kVlUgbY$QE8gq>)^j5HvnhLjpcI6u^wAu1CpS~?Vn&EIP zm7)Yt$6=fH*2ooskdw-}V%c&sqa)0lw-9yccPW+1^beh2G@YVt_8dy(GJX)C z={kmCkj-QW0&hYnCl-rMDd*>dfR9-gkF~cm)X>0_mPKDQ%CpVQY-?^N9gov*Sv=R+ zNZGb2hQlmW3Sk)Z0sq|5!M>&@g3eCv(lpljK32Jml`FFAV1#Y^Z8};f(X9a6kXU#$ zG&IoC(!$3+_Azd|?KXVhKkeL|ZdjJZg%@6ku3Kkpw?F^c_c?fAALUX3O@gLXlFukW z1^AwarHgZBx6_hcMk31^SH0sxuD)aC1Rb0$<|P+j#BcrP`?&eWD|z;rO?>em{*xE> z_nx$#;EVtG9bDI&z$x)ql*Y#7IhS*~`J7HpIa7jv&28@{(zS%P)($$FTQLj+P1Bjz z-oe6Ib0~@$(U;LQ4a>4fWd%>~2B{kq%i8+}y1x*weeUdtLu&94xl#sY>u3=jGhz^m z8d$Lq=rQJXbpnu1r`b9hpD&GQC!YTqL%V*)@Q(i?`NC)Uy(>0y z^~Fg%&%<$?`bIOIoKq2fMHUl9B{^EziqUDB&b*Ee z01o!{@SacoDc|_~XE05ZTrS6s7s_niQ{bvAV;A?G7<)5t4}cPaQtAM9SVx#TM%W;k zFi6BL%utd*hCnj`D3wY))fdHxXl$@_B2J7{N#kF?x4CY>0Jd#Uim6vUxLW+ZF&4$j zjWN7?2k*S<^{ju(JFzT{fBydWdGM*H>zhJ29Iku*|MI_oi-vfdL_CJ3=^P&z!1sN! z+3cipo;;q}lcsN959?PoGOPJ%I-9o;vO!7>)3h)w3(IQ2Ff3BJp3^2`rjm221db4* z;<+nYIIVE--D6?&Ek=I{+dO72<7$}%8zDS|) zH+<=@|Biuy6BrD!VPzT9?d8OX%P~8`3q2OdihW0-QQBHs=;`aDSS(^$7KULE1i_TL zRe&1=U>K-aj6x{HEYl>gEan0OK)z7G3j*$MYT}NeAs$tV*XTO8=JV`y9JXp28`|6X z{gDy=Qc5((Vb|Vb1@nqiF{Km)o)3}<)kE=koSSaCiBhS=(@#G=fy_@w^sehNI5^1l z*I&=W4?oOvdkbvYo#(Yz&D?I^dQB6Z&H8EVHhj+Pb|#}#((qCqX1Gj)CAj{ruP3a< z`PRSv2r183ZZVp$iymt)6{7Z@JR;yB)f82otM8-|YO`PH0Pz&Gyw89@-7 zb2(=+roxo2>vGxqKfwn-^LK3c;HPk1w>~-La+#Ia--c{k#9+3JG(rSI!}k@gukflD zJ~XM**4T)yTVyeL$M63iyy_9MTn^avLYBZQvFVvT^{j7C(IR9?8sj=G4F>H=gO;RC zB$~tuHKDX5y(5wfx;j`qro_09bC$A5=^`}804Z=d@tU-|nl@Zk@C7{f4-Qc^1UrI%brTk>AZQvFfnuuuj=t=x&cxm#MFnn zsW45`nDDH%e=DUZ7G0ivYJfkz>p6b#P>KZ?zJ_Z*IG+=HV(j?7;`oj{`+w&0 z_=qAO3X@y37}wD1o3i65_U_M3D(BqUa~T;O<@Qexp$QF53OW+qT(jmVuUX@B^=q5C zMmuI=Y7SM{Q6ia=EoW^-oEArVhdDwP-;8>?656pJ1^_l=!`nelzLX0v3KLg_jx z62a1Sgk@prI&q+@P~b_WIHBtlHI1(^!}i_jSC!pfb4`L9Z>)rr-}25`yzM=6dE0xt0C?-2i@5pM7IDo7=27qk z`K(7Ol_y^;;skKx+pgz*AH2Qp(a#j~ip$q=-5amO_X{ZHF)%nnK3A%H=^y^!t(c}h z!E?X!{WqcOavWbexUP5B>+_|IsW5fl_qqRxEj;|(esIf#s`bM`5TIJ;@yv6(@HRa~ ztfd7#@JX(}0z=v$6nFt>mGZICT!D=nA7k{`K~T`K_A;`MRd%+6het^d9w6fH*Xo|Z zK!jBbJd!aTJ!W7=Y>aRcE8L8xHIOTZczVZC@QZYHHgeq+3%PWm;F~|*$RkdamX?-D zW9^e+mX9AJUn=Xt3`mlC32uG&GQEZ9zzZq3h_nj;2-O_=k>+k{&#Gik!Nx zbNTwqSQ+{X>;L(y*dd#Rks*@mIKqgcN_iZ|r{sF<+n*=MmAPR}hI=1vK#Dk#aF`31 zE@yCfh=WHC;dx$tPP-2bpQ78MQlwp%U50@Qhe0Wx4TV^2n%F{65Q3!ZastR}8deaH zu92M(BpiosO(PbK(h!YuOG5)6J9LQ83xO&WIQYWAY3EZDl@mlsN$hH}I0yn_u^8!e zn%T2wbImo^uw}~@a=9Fi<1jipI$fFWDJYdnq}>9Z)NmzuD1_^yjg=V=r)aWsB=uHqz3t5y(&DRMzI(=)Yu8># z;FnN=Q<>*tnPSPU7YqE`*Y3l0{Rwt`_ka8p-w*2dGc-*irK~6O&vt#DZ8CN;O#MZ# zt5Op6;_*;ojP?@oJj&%Vu5uX878om(2$?2ACKw1{k(1^|I!cI2w+|C_5{N3+!^jHsl{r!|3XF}N}P(R|I4)YX`C{Rctu`NmL z8k1S=Hn0C|Be8}!pZnGVFf4=~Mq%N4YRURJ%}Y`y;gW4*(aMoR2?RPlV^lW%QjFl1s@ zLxy_Qerh(Jw~zto-_z_jZ`YdXgNoq>nOtjt#WEBxGw2jhT+T*O?C$fE6Lk$ ze;ZP2eC40NHY3bsOBbS)TmL!|wrh7!QA$xNJ13ot0*b{lAnI!;5(#nrn=a%22cACb z_4!gs{&bjCk`K@jgcA)o)r(D1%KBncO3}9VHMF%f;~^;5C$ZAU!&d>hQi)h|2exe! z4u|Vrmg6|2(hdi`J1*h9OR)3uoQU*EvygZ=ak2d8-SH9=3tR7zo6VcKG0mbI+ei7F%lO8Ej@)f3` zxNxCl-(dsKhm~DfHg#tZMu>Q#V80t zDhSAE8qZhrO^bk8LV#)F8U{isJYc&JAOt4R9|V}b&lfZeFBGbTgK{1Rb{t`-=j7rV zg^(IJrFz`Gc6rS-O$@`Rm&q!na2yBU_lZOzgu`JpO=I`&-CS|S6{J!r9((Mu`kZI7 z?yJgf3r>MRR$}hyLV&NEczVUN&wB-sHd0A6sUtOs(j;ZqV>mxddufD5y9pU++;Z#9 zl!|4(_=SI*7IV(*c2rQRf8E;JL@XX=bTm7~nyO`Js?S|0@n1jq1wjy?>u0t;&&8Nb zxAh>CVcX1VN-%cOm5l9u2HUplM|myTPE+Sx3_FSxlA`A$g{)jFM&hH$7fSeU`4rGf z#YMo0L(q5P)CcQ6F6lllSsguuu%kSG@Hpvwjzr90&9WpHUJ%2I=wRstrljoj)6f#- zrVZ`f_4OllBc2JSX`5WsH6K$z>)bgsbuA#&kVFZIS1M7?i@EN%Qimw$xkAs#1Gs_<*beUhmPV0;CTu!2=II# zL-#R-0^b8sA>@%%hUfS6))T-dhf`*v+wpPn8UfgriBf(&G3EPS^?JCfUz@IdZ>E?v zk206bap2%V7R+D3Xex#0d3^Z&@8LH-_9l)TILh;z`mxL~J`tY0|1jOTJejt3M$3gd zQPn~;HJNK9e>yqi@i@yaSkCRg|7HI84+hERa;%XqKx#6;+FzaSr5O> zCzJOPLSywsu(4Z5`T?^#+PVGHL;UH-*Ylab`3r2@uEaQnIt9}PT&3`os??ww1|=a7 zfGZ_|5ct4DYuBO~23@v|XPTfCW#Dh?sSb0U3TkNn&<(P z+<-s?)vQFNX%|7IT1x7ArEowqPzv(-BFFpsaEBDO2!k(q^yiP)OH8N4#7C(Y!!cc5 zowT(!oI>)I3O$MEO+5WpV&V#?`ruMdFXzia@~6YBd-A3of>0x~S6)h5c=YUi7ERM| z9Ea7{zYA%Fu)_&TzC?39WL4=3DEltMqr((ZqjiE9PZA-m$Ur{~Ptg?fiaCOXs}}Km zXNpl3!Phl(OCuc82!(V)VI4c9BMl85}|0J@JKV_~cTUDNPA zkJ8u}uIo@P=I~q>4aI8T$DTWn{?Qb7fA0qrN+n8;OUSm^8VV7LMv2A~bai#n+uK|3 zg%Z)Hm-FDE9!yyvWLiLgrUjLFt8_tx@LY$HRF)TB=;z6;eRXekyk4i3b6nD^=1tcK zTnI(rdn6kh$&BT2oFYP1$X?TA{pV}3@bP3a6=sd-M@L67O_Ph)uH(9Eui~0Fu4VVm z6C6J>N}(ty72p^5AK_3YMJgUAUCd5O@Z+&hhuPWQLD_Nn^G|<{k&z+B#>U9?Y^J0I zxIuu`5aUE&iBK5kb{YKW=Or5BFf^>#-{awU9<$opSP}m+AAaY1$v6cH#R9f%Pl}m6 zsqR<-ZZ+O6g{bzGQh26WIqsV#L3Qytz=^6C?+Sq%1n8v__&$Mc;|M{*Dl#x|stu_? zAvGPx4^FXx+I4p!1ffufSS&^|nIsyGPB;}EJ9dn_@4lNod-mXYUj0N6)=RGnyR8k+ z7f82ibDoBf5lgy;H{g@&MF zY@SkNQlq@EzngsDk@{{@Gd_SY1q!)J50A-4(()M_JOGBoKtne*?2tw*q7#ei#G^W) zNEm6vQNpIB)v6{)il@}DPKG%+Iz+LMM~}uB-v0uc6(Z8sUO9&5^9Uiao12Kw>O>ER zh`D8MzG?%b**wp8?`QMQoeT^OpF(VzOa{;M2M5RHfh z&t5ferfC|{XcX6VnLT?p@pv4odU7~&`%)R>#vUp)z zo#dm@FxOtQp249EkNkXV-Nv1=%lE$jD6TuPis>8oK0vADoE7(-t1%g-u4x*ij+3>+ zw9UT&-%Rkr&MO zmbsTw(xBx)gR+J{*#nMwlB7FE*w#>*24=;Bk41G7QJrwuMmOW=RuZL0$y9gOTFK{h zm_i7$(m;zfGT({O0 zx8CzEoMMTiBO^S$cOT#V?)S*&^AxIG36nFB6Tq;dC}DEoc%H6KgBK2r&>7J=o_vh5IVc}?ID>=)*F|dPR;-@0HfNVOsL9zkxttt?l_fBl)jGw zd?4$(WOTh^(^a{a6$(sb?eq4 zM5XG)aU49)!!Qim+uLbtYa<*Eqm<&|hacvyyY9ku-3d3n3xxujrp;)5z7lp@_vA|g zRlR6bPAi1wqx1^vJEJAEkV3cu-II8}iDwFgEAWaw6eSOS_X&<3>aCw@YI0A7xoz7n zZn<&81gECCse!lNdNsPH@w10FS9D!=PRU>Sen2i)JYzY}<(LXn*L5AMFife`PIh#J z*4bS&w|7x2WYIK9Lt_)6a113i99JP#P$?O36|Sr3?>ox&XE#wkei+kp&}uQqYU!M* zE1E19<$}!cfyo~7Siz>frAXY+FfN=`I(P>t4tG-@A`zHg99B;B!1PjPJX355Cscxfa7cUHRqd zFe`CsaNHv4(P4y?jAhgG$&2~L_J>%xR4`U7bF|Mv;L>y4C$hj`&moV|qK%8e6)P5V z`=@vF`YQ_b_77lL7N%*E&*!lWPQf&kA}j>0N)aoUK}yVO&y))r8fYvQ!F8clRtsz^ zm57;Uy%GmtUo=YC_eldD;LV|Lo6LwQ3b>)~unkvy*&2 zPqA3UFbtB(%8k>lTeoum{rB_eqmS0h`f7y{x~`MY=h3A^aOsnLZqd< zkCY(w%IA1l2jznB1)49=0u5;ZzQ8L7Jo5c#=skRbP$)zqksurnlTN3nmGh~mcktjt zn|Q-D>*~o=%QESj+sS+1djqp)xADM(Pt$jN=(H7UQVOEc5SdKA?&!>v`_2`~Pll;W zDT!$TxzPc7cRq=3nKU+akZ5eJPL#w80)!Xf;v+|5=J)@SfK`ND~{BnjE*TD zdHP8Grq@g`Yu^ikfU=al;JWOW679qQk?w;eBN66xba3gaRjgXJjL-l6@AK%h&+wg} z{FH4wcd>2fF22Y8l^wph8QZq$?d`3!$W@B2Sbj!wj$bgkuG5+{XbPg}RtQ-=+SV3h zXq-OBkE!IWU4~Ig@z-DY2j2Gfcbt{ceDAyeS+A_BRclO!Su<*YTQ6P1p6*@ba#AbTg52aBz?d7AfMPU(%8jNOrHtlpV^(ek*z%)#5zw}84hAyR}eHITq`UsY7)#qkzG>Nuy;EDwiu&H{-6>rE!3y&ifQf2BW{%aPCL>xuN*)%Q>+glU>Mjx(v8zYMz_KaTgb zFf=p-D2^Pl$>;Or^C=>c2)m!nRlm;j<_}&%Sroz0(3Hj_Kio{;k%2nFN2AgD9gykd zR7&yF`=6k*qmkvyy6X0*>l#hTIJdp+^{iXBg00)S*}eM!hYt5LJe;PvIm!I_oirw+ z?AmpZbUJs&+;=XU=K2^&4|32cQ(Ac$&7Jd!BoYW=qlAx80#JCaOUlVJ zbo2lRpW8&C|1b$Bjcwa?Pb>%mip3(y2+Xnv$mO8uaQ9<_OqzZ;GG_AgqY-XhTP7CO z(8D@-5)?Wf5C52*vxSrQ;xQaEGuIHx@KES5Uo4NTTf6QNehegy28F{mpt}xE7ng`8Ai(y>kcgghkh!MSOSTmU_r!e0_TD zGb*=MC&%=CA6?V9b=^uf?|Kg3_i1fyB@s^WiMxKlEjQlC(xr>o{M_~l;hCujemXhB zkqDmWF)%QIQkD74jAbafE(o3eQX49tz$>Nkl#3utL)ajYF@%ydH#T$or+4tW%a^k8 z*{3QEz-$}GaVEvgR_%L_Ql#43kw8$5&kHHhs^Oc;yA%VY5a`u6TXX>9+gy1<;8pV+ zGg&K2Dg3~vRL!N-`a=Qa^ZEMRj_+YptDmoRS{+|%d8X_0<+j_CJ>!~erfJsKs%_gC zhEaFyG&BM?!1Y`nePAocj}A^CcumtP>vM*3?%j8UZ`^x7H@xX`)~#Dg$hIb|fd%v0 zSU7(+;&+CBF2VkF??*>p3v_mm&<|jxu`RRH3Emm*i?4- z=5!Cc=|~vE(s=zv4y_RzQ;(tB3D9DcT#K=s$B!S|$Jf5|436WGOeTrP<1@yrT^JZo z`nB?^KmPJ}__JSs2fpt!me2FKfB6d6?%T($H{Z<7cJ(l-@CKEkpAQ=-{lYA zb$t~xjWs%RImeH|>@1wj2+h$9i<^UKCv&E{9WU$2#2+{w!Vr{Q$T?~P@s20pnsMjz z`6)3&w#`k;7qWTxc9c@gU$6jInS6WG7K9LdEG)Rpab=-={;<=%w1!t4i``G@nwU0w3R3 z6Xv(pZ)bc3)p#4I{oMF+%ClXcuY}#!Hm8P$hC1Qbn#k4U2!%rUzK>y>_@3m62X=7c z=+J2i{!Hb3ZhJQ)BN=w>KFHcN7tq?0q_HtUBoeMT5}8p3heqk^8(`P&19b22Wpp%8 zHdlN}-1kxlemYEje2rx|9A=)bGnVgXWY;lLd!7bSNf^}@q*MWhR5Vx`@sNpOgz6r= z>$>D}Ih69adU=6lc7*LCsL>3ceRhQ5=^oe%;OBcS4viQro#ipNGfz{aLEdpV&{N>4 z9mjd*xg$7kh2Y!T+VDK@tT2TT{Lw#si_ia7r6cE`|K>ZZeNvqITZJBe{0TNbvzhCz zy_QTaS5NW=LBJo}@g|h=c!htMPIhDuiyAdNPe(Ig?|;strPboU z9(DQrJ%zeg?fd?W;J)T|Hg+HNu}7cci*H0KT{iW9f$l_4#zDcHJ!0+mU6lBZUM)2 zvFu9HQ3U}`*{S6`F-;58G>ApQ?CsuzLQ*c5s?Qp5^@_>oQv+IqfVONFA`#Gaa#CUf zg>o6UrgJHgLqh}|9h8J%n_f)TK-AYw2*EubT*GgVrjNgk>O6y+g z`h2LNsE7fJ`P& zCX*+f$&pIuNvHGYM7L)%W{RoTVmafzgG4k;G-RF9N4;WH+JvKatwgW(2AGa!jrB_k zghqRLrW;NS@M}AYJb1eJ(Rc$KPeg|X1cwF;3L8gBrw>sm6zaqq3WaEDuC(|q7K<+l z^K&1*?G!H;;FJGwFL(XM?e$k}eeVZ9sCtUUdL=_=i+01*>MO|fYc070YTv7xiFeaQ7)I* zyMI5HWzpWGamDidl$b@wq2Ko_-6tIfPboYhFf@(9(NP*b4`o@9$q=-*PMC)#*RAN< z^XL(RTvfL-wIR>eu`LTr*CxE+<#acd$5$uSy!&&pK3`6|osJVu=M?PTbb^6nDQw#& z8jWIE)&#qKshEe4oZ#@06O$%7&!ujslJliv>X}UDv<5OB{B++t`QnXj30`-J$)c7c zWP5Tvu>*Cyk309d{QJqjb0(PKaCkzkYYj7(%e`!ve{jc}CU``(8gbwE>zIpMkG>>K zfPOz<&*6Z(f0COJPkk{qUiqC!*x<^ulym&Cu4W|Jd;uXOf#Z>KvJ{KO3GwmDd`ez_ zsl~#UBjl#RvoeZDIAw6{Is6`uh4N5Ym~>XW$29 zi(^D$2|Ta*!u7z%4}wa4L?w+>ztrb@E{36l(D7A3&xsSnqBd8q4YPb!&$M!8G8r zZfC+ngM*cF##(_uu~;Nz%a?@{ei__%t}yjk9f@%_&4S8eajSp(LA^14wdKZyk%$@0 zYB8DL;n3CAPdpf8>sEN?c{ZIm&Swv)i91Sd{Ayt;;!%xREjIJo9lF{FNT@-!odZl? zf}u;4UF$nieFiCLh+E8Qvsu{bGOuHR#7mUZaaergVVIj{P^MWLYw5kl6 zpi>Ae0fDT_iNKarE~QpI6jg;kYs~R-dI6n953A@AKm}7)bxRFMpfrK7G>C*aY-n_s zy5*p{FCWZIqOJmxPCGYA43rNp>$J0+?a9^dm0qttobp2s|o z`7&X4Z~W+?aY@upRA4Ekf*=SS75FL$d|L&9s9dyCD5VrA0Z=M9hl>Teeb3k~bz_qq z(I4CJ_ODKhDdw(NF(E?~R4)gqdR$XgV?>-%uBDW!R8iw?#xF%qI}*VRg1 zC4RL8_`Kcz&&K@v=b~ytOx~}=PJ3k=0M&R)7y zO(68zWh7lk)XGm!dhtpS1eEi6in$zt=OLs#Z@2%0F_$l$UB|5SFO?`ID}N(u2Zd_h zb>icRpnxf}G=;KUFdJUG29mR9QSxSQYHMry?B%!p^t6~F-rTHCm2qkzPw@n+ULZnX zg~Np7am-LiMH(9J-0|?k|9^;NHTfn^N&0-W8F^o8pH7?n(-T-6^TqM=c;S3Ri5Jz`2LGFGRYg7>fV~? zQ5YK|J3Ne2D!n-W|4r7)dCW7zT()f4S!0fGTOo02PYkhcevZqRgBxC=7R>LubNy{U zI|WlT&6=e+gHa>Bd8<|tYieT0Ll2#D^w$i7L`w@+Btj?_yK~3G4}Wd^XN<>;x3ti< zU;&Y8qp^HC&2Uc-nZZEFyEg$O4ScRv5fBQwHOO4UDW z`~s?9Y?BhtaqyfM`+`eNL(_G1)0|Sy^|#)t%7sGxCFrNa@Ld;KZSGd{_JSawl*^G% zrzz!f6BhSObvxc3e;GFPYQ$`wJC~8(-nza1D#&^1rI*f#uOB69m<{dibgf*8kdo~1FrMRJMIr$7?b}CsU;w@PKFdf$ z1M^m`LN`r{*(|>2F?jee$Gf}HbRDVdGs2vd+=XEEb=UFy!w(~*q;39uqK%Cl*t{9v z^H}qyH}Tv94^(9Iyfcz>{4hfyn&-@^>r0L68d$qo>p2dkY?i{ zk!Wot(b`HV79%|{K)S!5a-nd_sqsuOH*DB&)*H+C_3U{bg+iq{pC)0|yc4|p>HUKnZY$-o(7@)89D zB+q$Bf+W8ouX&h%kYA7>0g}f-fCP3hL11GX!Je@#$(BS*vbcyMn`H0%-ESUlonrN6 zZ=@uTjranDC7I;us$2EdIp6utscaUxg#{j^n5-p1x=;wl&46~?INP-vJjV$;u>*zI``~nREM#r*fu6_bws7>O|03Qxo=y)0dPP;?xh|b( z@O}R;fA&{@m8RcIvFH@sn-CyPGR{%&QVCtG48|RY7i@UL zoW>@3r`=`~tx6@3tG)g@F8=68Sh#!{kys3#>q3vm(KtHdVD5PyJjX%1R)cHXP&5s$ zZKKy}5yw5$W`1!IdOQw29>?~*dvI-=Q!3)2uIV~7UFS(tm0hAi^uoAt(pn(kqu)z_ zrfOQ>p&3mk5sAgnWsRxKPKS?YW@Y7=?htHxu6uHvEaH$A1+L>j({(7Sis^IbP&j{n zEYOQ!eB}@RfIBj$S+@(9FC&@Dop2NsRfQIfB2y^f{PpWEeccXwT*u)+KexJy#Vc3( z=Haw9)6>&9fBiaA)6-~It2lW2l;hK&yrgJLk|Zo$y~^Lq%N*yphi?656+-?}q`@WA}tA$Rz4o%l@ znw`#{i674Fbb)%|^R>UCJX9;ZYo7eh9? z%_btT*g%`~4qBB8T-(O_ty?fU9e9p|SSl5OI+HGn@;EIuTxUF+T^o&)08{u{Vj-dnXtIo+no={b-z8cLANdrUhui>b`o?L%{Z&7mVkR0&(i z-JLoTq9!tu%}v2Msb#*-aEZ)LKOqpC?YRgVzPJC%w9B6=BlOnFG-UVDee=bVQ=Ron zLI8MzFp>h9c%`1Y~DAH|p{Y5rDWh#!8<{MHnzaNFK6>N3cRJqd*j_ecmV zp5X>IfV-8sq(c{m=JfY>%n(<0AlAUzxbykijpl-TYC5yfZnq-fvHH)1*${^7&5`oY z)R3dGl+(o3glp&Z09qG-QRiZIMtrmnxd3wABnWqzx!{K4JF7?QLfYG zjsY}jRu%(*GI-4Q@l0)hRs;V5F1poqV;CUr<{Z%oaf_G=xh-%yHvi#4VN)ZO3Oy4E zQp{ShZz{vw6Xl*14Ry@jg85_mBoE}K&OWkznPO9Vc2#sYDK)RysNX;J+PugB!X_yi zUDYn`cW~0u@dm(EvN(b!n~uEk^J%NGF1f9bcEa@mQqF6gBi(OesR3pZe)dd7TN}@b zCvQg_A9YTyT~V|rVLB4#Lhnw$Kn2P-Z2jm~7R1$oplt?1Cu9?=?9IE|S==qym+*sbJ4jJ=p-K<87Y~~{w$38FO|L!j~WH8_D z2QnwLv=$v4{*F2X_%BXLJXqHBB?n{F2yM%*KgQaC*wnWv(tt^>P+g!?-sRbU%+^&9 z%-1InUIxdO^#mkoK}Jp<2MsP~D;kIdJkFwlZsdQ{O=y&k@ZX&pgjVeAT(3$!x)3==9j(d8IUGs* zP1C(O?I7sLLVvtD|2$?GWpOt9g?C?hjdep>7X-g6sAQuE9YuV$a*Yow9q{hG*p!0% zBfg_CkcsdwxUXj4dQ0?iod*NJn_Wh^%SiwM#Gc+2%z9_CCK+E4qmCvHU;*k{7xrw8 zO?NLUf*l*lmUwtGp_F$PzDq#CUdq5f&aekRl8aYJ`uY>#9_AS5^d53d8r76=ER}g( z8L{5g66GLv;ROnJrZzieyeCcs<$oPdg>RXkPpQiPkv5(>=el2% zgG!-@U>A!J3X)xY>JEo&aKO4TnFr1ufS@U!GlzRNV1Yyxf)Yx zp($XQEcZm9()VH@gfU5sGi{4Q@v<`}l0_#d9cR8}!;qG85z-Nli#Oq2^scPtHR9&v z@qD9t199UlgLo@8YeVtLZ>t>JPy}_alsqQc=HXb8Zd9DiS1r8wk`gMYqRB0Y$bVG- z`9ZsYClOI*c7ZYnEkNr*FrYtXL|}KfUPrm~R>M~=btV%}S@{T^2j02R2buq?b=))R zq0xiO#d3m)r-ed=GQNk5AZ%Hgut|OCQ2Ap4J?jmjD6QF+Qh_ewLp;Y ztQNhwX!a;D(XFJLrD;s}##+211kzkGG(oFlYl{n*k-(e$QGcOT7-gJCVlHj#Zbw){ zp>Y&D1g-~cFi*6H0GiWj**<-uYcy;Q_HRDyS(7K(dfMpitBge4**@E>$^x+K(1o4V zZ<40_qRGK|U>z*5uu-PO#%WQxixHfffgkvUQIeFEdI zSRpB$Wc=3F6U3s6$lKomDs+Tl8p-}%$X$#3Z=9dIe$#$+rTgOe+>kCm8s0oE<(Ki( zqaUR0_1rlZSfB6RQeD8?YhNAk^b}@xE@6qYjFzctpyEA=fG@NFxKh6&A;nXgjC6TV z!wH*lUY=f%)4pQPU#CGPPMlIuIXQmb#4_V(V-?~cPAk}b)Y1VEa^Jg=%0NB)S z@ZSFS!i3#f?JN5CiyzBog9}U&M~WPmdI!pL( zeKl1S8zYyK_v7XH`9kO|y)j3>3|cHF1;YMZ>XG067)LRLM|sQJIp;iRTgb-NHYqP> z3+BXIKt?M2Y6!3t!dEgqiftnnCZTMcaP={sL|Ivue3NhI zR5;Yqu>M%eYi1xwl9Y_I7mg8J4V6i%Cgi6@zC{1H^q;3i3J|;-;C2R)6I@uspiHFP$U-$o7khDR!-!Uv>t2EX|>6iLr1aR?FMqYVg@Q=YzL!=N@KEz zf+K$AB?bQ#+cp%IO6VS28^v}+!)Yy)#wq69-TW;*WA(u zaw>-ua@y;Byof4|{pjeCSC#D7Cd3Uqw4zs768nml2xKHp;yV7{#o?@rV9JH86#;8S zIl%h?)Q~CdOA5%#Zrf+v#^=Fve=fz-gbCM27E2Yj(7?%0j5{lO`)74|xm1+I3dJ*p z;n^O4^m8cGD`uRU{|Qu#wuXVXnUiw*3T@qe1UlqMlx)DxEbf`bJ(Sw4>Uj~T5K;xeY z5aUuh`y+j7YeW+h?i!z7Gk*)Gz!<<{^=F0*$kyn|)vYjJ>kUx%vGPMb+BbQ=;4k@K zvjqoc9)s;>t!;iO2qqyjQWZdaEOsCQ(-otQ+mjCB3ZGE&r% z?WqCDp+;rExyYRc7}d7?P<^VB`bjE~_LzjNy1tB<270nb+w$^Es2<$Xr;xKT{I-hH&R3f!D8gebS1TX@q71){rO7TZs{(*0anK^D+q-g1z zq1IWG#35Erp#EyZt}%&*Q%ACXm8Ep0{HZxOcaW>ph_?^=ku{790!R4_P?i)iFd*n{ zbhfxRX&p{akQ7B@Og6K2uSy4x`Kn_hIpnP3Ug>^ktt)h>JUZ-yYFh8^05@KosjCA< zXg52U*OpS-;jsuak70Rff=hOny@~<#g)zVLO83MbrjQUFZnB4$dN0!Zx8oWrOQW{Z zo-ySLmN8P>_1j?WQfh5sT~-F6Sw!Z`mZSK^keG0n8b{JRI10#3lDh0bCoH#;B4bpt+ zp#k%UY?SyT{nVs9>(CGrbb5s4ucWfzsYkqF0($trjHCAAmEmwzJb+T~X{b{^=z&CN?x0 zmGS~8Gh>l)PPYaK9xsLgHSH>Q$uJMsh(PzzS9 zD*>gGPiaINyFLOV{MC;M*c+h9Gu3Z^D6A*K10*xf6_$n;>!Jw>hs?)hDBJcSDseBt+$?nuTBMbYqw^i{->2Z6) zK(`wpyt?0GPdlYg{0nF@vvamEF>^?@THrzDe!SBD;RBPCTjF+sYL=8*#&JDpAIVXp zbqY9l>pHPcG{q>3t1B)k7|U-zTEsOMFy&wuw-WdJpfy9PMaWe5A4bb6>VHg;YGsif z2_BubT${l3pZB5A4c_))LXwP<+&-^xsywMQ;`QK-iCJNt|yM=#3J@QfHdA@39VppXe0w-o~)K^cER8STN$ zXE+on>!;6U5&}$2FLn0N9s_N?O0qS+P>i{0( zOfi%RPj~pxIQ}8{bUbZqu#RKH-3g7|>ve4t?!oNp%9gFdnufZ>@Z+Ez=>It}IyF`7 z;T>sE77qV1tjG$eJY$hqgZ8hSO?G+9jncGn98*u0RRCm&Mg>XMS7E;UTwPDXUO9CJ z0~i=fOOTSljP>*wN!BI+X|Vt#+{n)djdITSRTpjtsdu~ZFF(L(k$cU?Dm$M4ZIMg) zBghngUY)bH5192jILA^x3y9G_TySchhNJ;ureVP0^REy=b|6aF{Pd*q;Lrj{DF3@! z#}Yu4Sdu6nut?kHme4*7KKb*(L+#_sO9thegZsNJr^yA3r=1;t5udH$s`^#MrhC}D)Q?Ic zbP^>xiKDV(>i6Hdt#bDbOdym3<5zLJu8T2zNV#}D*BZAac52792(Ap07&4>S(?gVD z#?MeW5PQCpZ+%ViC}8RCs(RkVFcGz^h%Zh)zV;!;qk5~zG!g$~P)|c*3f>&M5=|!5 z*%1Eqz&VtKjf=GCHqpN4@1&^M(vp1L_W%d4Kw|;qJlcX61ENGWr_X@kcveKD?s_51-k^)NeN-@NN zpxLr;QLUj9msC^~L$!Y=PqOX$s57(2k3xBQIe6pJXhfA&{cfd7p}_krfA=&*7I}7ah=9Z}~pl@pQ_V~K+`H1@|`LnUV zF$dNXEk6w!X$b`c+xVy4Ki;DXmO{YnyH&icSL?N{8pJS595El=Ier)`Sf9dUk=3IH ziZ#Lt^)6~t*~EnV_{h@LCEi!H6r~Dc(XP;z(mKNj*bekGyu$OaLMEyjZJ(~jEfWYg zl}3sD{gm)Y?V8}1cpH(YqGLH{z{zGB+)~~lRg+?UHVU(c{)IkpZBBPwoTyv>0el9M zp&StX>EoxJh|-7zhch;APw9R&5-l2`jv@dbS2Ma+J&r#G+G9rXj0wNCqo~(Qh-uo| zKt7?y$@i&?#AtQvVyD&>wEQ=X5yQ_8fUGMO7X_OhGPrXT{dM zNyg0E6?L`%#0Z@vYrZF|PH!}tdD~3F%w5*$daB+n>nkFYQeLEPgY_4=!a*J_gM29? zz}0u_3s9P}TbH_(`#L$bY`JJW&S~e_ZP8yJUNUPaXAO-+{`{VFF;CVL73q!AZBguy%oWC5R79Z=lp5vXX{VKBO~-P zB`j2PRd>@};cD92B^^C1O-=Zm`Yr>#00sct30t>qnIF%!+uwuBeJZdE{HQ1vFHGr} z!-6Wg$M%1(w+jFfu$vs%MpQXI+l062bP+?XSDUVcsyEu-A?o>Y$?wC3KUJ$0!%NQ5 zaR{ZoGL%H?KU%}5!hK{s>B*qfIT^*E(Ao_Fvl+uPUj(GLH%HoQc^5|0B<2;O>G|!l zxrhgPZ=1q>YrQFIq(>?e!!{q^|1l#AhJFvDd1FP3VofkHpf2?kHhh9xkF;lpGflOdL>Kp%NKFH-U-fVd~=;PQW7|kIU5a#jz zJHvmHcB_>(^tr3#GHVVy>AVrDd>RGj+aqD?-$PG8Eqa2| zbF&;>BQfYvL~$phYL8O`D8833lV16-^zf9rPw3*m{jG8&0rG{p8zZ_mpv7&(t8sa?f) z`aSgFGJGRTkU;A57VS|GQZ@F!2~O#dQB?Z)|)IB z`iD)4sh*{B@zm&R!?Oz-NU>vd2O{~$2# z`%SU}qT|^Jbh~@rTl0?3h5UcPSfo0O;pL!5RDNePC-zhYhX?EC)jqdq>8Eq$)aqQK zQ9Xj7X$-$4jyR)OHv1ddC)t9x!9=}QsPiLW&uZCgh0J9Z%tv$Gw{zUfHSKo3pm~Dj zMG10NP4RZj34kGaB6HYBRH0>7m%lWiLmt=2p7k5#QM>D!SXl_&*9>bT%hdjK4%Niq zwTF-%ZPjawx*(KuEo!|~lO>;{F9l?tLY~Ip#NKFTZ~gK|Jq|%436t-#%YUx$lMQ72 lYp%)LjjR8Em|+iiB#7{royBqyz}3+pRYfg@TKTu({{x&%W^4ce literal 25434 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 literal 21281 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 s!mx^yn;QuDS&gSS5a1-!rHS^xk5 diff --git a/projects/mtg/bin/Res/graphics/simon_pink.png b/projects/mtg/bin/Res/graphics/simon_pink.png new file mode 100644 index 0000000000000000000000000000000000000000..1cda1af0980664e3dd6ad67ab390a3399713d5b6 GIT binary patch literal 2438 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 literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/sets/blue.jpg b/projects/mtg/bin/Res/sets/blue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80547592733ca9411d400307d6dc2366e3fd0468 GIT binary patch literal 11875 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 literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/sets/green.jpg b/projects/mtg/bin/Res/sets/green.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c5ab4845276e543aee8cfe1cb22a650d8c8fa5d GIT binary patch literal 11770 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 L8I^7wkMsW@LE2Q( literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/sets/green_thumb.jpg b/projects/mtg/bin/Res/sets/green_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..399005bb28a435234d61f1d3f13cb0e3e54985c7 GIT binary patch literal 901 zcmex=pkF%#4BzOoEKef{g!FL-BO3=$Qb&M+k(rs9 zk)4GZD$mHo%)%*#nY8X>D*raNmn0A z2JZ9Ud0qI#hIGsiONuv*d-(r28I) z779eF^SjS^mXT`P2^=yquy_S?D3BDtO(T%w}NFh4j!uf*G{ zSvgkWxVl@PbH35iRo7YKm(8&<@@2WS;%cSIicJzruE?Zbo3!m($7;a3IUQgnTekm9xN!9|buU79Tz(A~N;k}L4lB=>cTYUjkQ Mm!5Mup8fw#0C(s>LjV8( literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/sets/red.jpg b/projects/mtg/bin/Res/sets/red.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95eba7994099bebe4738d924a2b77c163df2704a GIT binary patch literal 13032 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 literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/sets/white_thumb.jpg b/projects/mtg/bin/Res/sets/white_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..943bbdbc127f2831cc58a925b459749ca3d307aa GIT binary patch literal 830 zcmex=pkF%#4BzOoEKef{g!CxR;%C2VDy(GOV`;KT8Mo66M+k1ZH zdc8Vt-{ZVfoP8fj7E0#^2_|LF^2pJWJoWK9bG+l7FLGN0KdJnEu%pZUQRJs*o*h%7 zA|}hU>^ZgeiKfas{#SV%FRFs(zAbB;m~iHH^MdK3k}5KcvWspN_B~kf{{4@&+Pf#+ z5q3458nxE2ulU>1!pLu@Vg>dY-F{QCeeQ=xD(PN|WZZafR)1=%?2Y&0l0CP? zoO_cM735a03Ujg8c;)`$6+$!4Pq43!x3c$W7t0D4aO=38ce?LO*_^N`J09KgGH!DF o^>^jU #include @@ -29,8 +30,7 @@ class TrCardAddedToZone:public TriggeredAbility{ public: TargetChooser * toTc; TargetZoneChooser * fromTc; - TrCardAddedToZone(int id,MTGCardInstance * source, TargetChooser * toTc, TargetZoneChooser * fromTc = NULL):TriggeredAbility(id,source), toTc(toTc),fromTc(fromTc){ - } + TrCardAddedToZone(int id, MTGCardInstance * source, TargetChooser * toTc, TargetZoneChooser * fromTc = NULL):TriggeredAbility(id,source), toTc(toTc), fromTc(fromTc){} int resolve(){ return 0; //This is a trigger, this function should not be called @@ -63,8 +63,8 @@ class AACounter: public ActivatedAbility{ int nb; int power; int toughness; - AACounter(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, int nb,ManaCost * cost=NULL, int doTap = 0):ActivatedAbility(id,_source,cost,0,doTap),nb(nb),power(_power),toughness(_toughness){ - target=_target; + AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, int power, int toughness, int nb, ManaCost * cost = NULL, int doTap = 0) : ActivatedAbility(id, source, cost, 0, doTap), nb(nb), power(power), toughness(toughness) { + target = target; } @@ -1962,10 +1962,10 @@ class AAladdinsLamp: public TargetAbility{ int nbcards; int init; - AAladdinsLamp(int _id, MTGCardInstance * card):TargetAbility(_id,card){ + AAladdinsLamp(int id, MTGCardInstance * card) : TargetAbility(id,card) { cost = NEW ManaCost(); cost->x(); - cd = CardDisplay(1,game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); + cd = CardDisplay(1, game, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, NULL); int zones[] = {MTGGameZone::MY_LIBRARY}; tc = NEW TargetZoneChooser(zones,1,source); nbcards = 0; @@ -2485,7 +2485,7 @@ class AGlassesOfUrza:public MTGAbility{ CardDisplay * display; bool isActive; AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source),isActive(false){ - display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); + display = NEW CardDisplay(0, game, SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); } void Update(float dt){ @@ -2979,7 +2979,7 @@ class APestilence: public ActivatedAbility{ for (int i = 0; i < 2 ; i++){ MTGInPlay * inplay = game->players[i]->game->inPlay; for (int j = inplay->nb_cards - 1 ; j >=0; j--){ - if (inplay->cards[j]->isACreature()) game->mLayers->stackLayer()->addDamage(source,inplay->cards[j],1); + if (inplay->cards[j]->isCreature()) game->mLayers->stackLayer()->addDamage(source,inplay->cards[j],1); } game->mLayers->stackLayer()->addDamage(source,game->players[i],1); } @@ -3489,7 +3489,7 @@ class ASoulNet:public ActivatedAbility{ int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); - if (newDead && newDead != latest && newDead->card->isACreature()) + if (newDead && newDead != latest && newDead->card->isCreature()) return ActivatedAbility::isReactingToClick(card,mana); return 0; } diff --git a/projects/mtg/include/CardDisplay.h b/projects/mtg/include/CardDisplay.h index 7a00520b2..f8a33c334 100644 --- a/projects/mtg/include/CardDisplay.h +++ b/projects/mtg/include/CardDisplay.h @@ -8,12 +8,14 @@ class MTGGameZone; class MTGCardInstance; class CardDisplay:public PlayGuiObjectController{ + int mId; + GameObserver* game; public: int x, y , start_item, nb_displayed_items; TargetChooser * tc; JGuiListener * listener; CardDisplay(); - CardDisplay(int id, GameObserver* _game, int _x, int _y, JGuiListener * _listener = NULL, TargetChooser * _tc = NULL, int _nb_displayed_items = 7 ); + CardDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener = NULL, TargetChooser * tc = NULL, int nb_displayed_items = 7); void AddCard(MTGCardInstance * _card); void rotateLeft(); void rotateRight(); @@ -27,7 +29,7 @@ class CardDisplay:public PlayGuiObjectController{ class DefaultTargetDisplay:CardDisplay{ public: - DefaultTargetDisplay(int id, GameObserver* _game, int _x, int _y, JGuiListener * _listener, int _nb_displayed_items ); + DefaultTargetDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener, int nb_displayed_items ); ~DefaultTargetDisplay(); }; diff --git a/projects/mtg/include/CardGui.h b/projects/mtg/include/CardGui.h index 672b8f66c..763ccce90 100644 --- a/projects/mtg/include/CardGui.h +++ b/projects/mtg/include/CardGui.h @@ -4,6 +4,7 @@ #define _CARD_GUI_H_ #include +#include "Pos.h" #include "PlayGuiObject.h" #include "MTGCardInstance.h" #include @@ -11,10 +12,53 @@ class MTGCardInstance; class PlayGuiObject; +struct CardGui : public PlayGuiObject { + protected: + JQuad* quad; + + public: + static const float Width = 28.0; + static const float Height = 40.0; + static const float BigWidth = 200.0; + static const float BigHeight = 285.0; + + MTGCardInstance* card; + CardGui(MTGCardInstance* card, float x, float y); + CardGui(MTGCardInstance* card, const Pos& ref); + virtual void Render() = 0; + void RenderBig(const Pos&); + virtual void Update(float dt) = 0; + + virtual ostream& toString(ostream&) const; +}; + +class CardView : public CardGui { + public: + + MTGCardInstance* getCard(); // remove this when possible + CardView(MTGCardInstance* card, float x, float y); + CardView(MTGCardInstance* card, const Pos& ref); + virtual void Render(); + void Render(JQuad* q){Pos::Render(q);}; + void RenderSelected(); + virtual void Update(float dt); + virtual ostream& toString(ostream&) const; +}; + +class TransientCardView : public CardView { + public: + TransientCardView(MTGCardInstance* card, float x, float y); + TransientCardView(MTGCardInstance* card, const Pos& ref); + virtual void Render(); +}; + + +/* class CardGui: public PlayGuiObject{ protected: hgeParticleSystem * mParticleSys; int alpha; + float actX, actY; public: MTGCardInstance * card; CardGui(int id, MTGCardInstance * _card, float desiredHeight, float _x=0, float _y=0, bool hasFocus = false); @@ -22,10 +66,13 @@ class CardGui: public PlayGuiObject{ virtual void Update(float dt); virtual ostream& toString(ostream& out) const; + float Height(); + float Width(); + void RenderBig(float x=-1, float y = -1, int alternate = 0); static void alternateRender(MTGCard * card, JQuad ** manaIcons, float x, float y, float rotation= 0, float scale=1); ~CardGui(); }; - +*/ #endif diff --git a/projects/mtg/include/Damage.h b/projects/mtg/include/Damage.h index 24e4e49cc..daa929c34 100644 --- a/projects/mtg/include/Damage.h +++ b/projects/mtg/include/Damage.h @@ -28,13 +28,13 @@ class Damageable:public Targetable { class Damage: public Interruptible { protected: - void init(MTGCardInstance * _source, Damageable * _target, int _damage); + void init(MTGCardInstance * source, Damageable * target, int damage); public: Damageable * target; int damage; void Render(); - Damage(int id, MTGCardInstance* _source, Damageable * _target); - Damage(int id, MTGCardInstance* _source, Damageable * _target, int _damage); + Damage(int id, MTGCardInstance* source, Damageable * target); + Damage(int id, MTGCardInstance* source, Damageable * target, int damage); int resolve(); virtual ostream& toString(ostream& out) const; }; @@ -43,7 +43,7 @@ class Damage: public Interruptible { class DamageStack :public GuiLayer, public Interruptible{ protected: int currentState; - + GameObserver* game; public: int resolve(); @@ -51,7 +51,7 @@ class DamageStack :public GuiLayer, public Interruptible{ int CombatDamages();//Deprecated ? int CombatDamages(int strike); virtual ostream& toString(ostream& out) const; - DamageStack(int id, GameObserver* _game); + DamageStack(GameObserver* game); }; diff --git a/projects/mtg/include/DamageResolverLayer.h b/projects/mtg/include/DamageResolverLayer.h index 7fddce436..9c5f4e0fa 100644 --- a/projects/mtg/include/DamageResolverLayer.h +++ b/projects/mtg/include/DamageResolverLayer.h @@ -9,8 +9,10 @@ class DamageStack; class DamageResolverLayer:public PlayGuiObjectController{ protected: + GameObserver* game; int trampleDamage(); void updateAllCoordinates(); + public: int buttonOk; int orderingIsNeeded; @@ -21,7 +23,7 @@ class DamageResolverLayer:public PlayGuiObjectController{ DamageStack * damageStack; DamagerDamaged * currentSource; - DamageResolverLayer(int id, GameObserver* _game); + DamageResolverLayer(GameObserver* game); int init(); int initResolve(); Player * whoSelectsDamagesDealtBy(MTGCardInstance * card); diff --git a/projects/mtg/include/DamagerDamaged.h b/projects/mtg/include/DamagerDamaged.h index 87fafcc97..4f6443aff 100644 --- a/projects/mtg/include/DamagerDamaged.h +++ b/projects/mtg/include/DamagerDamaged.h @@ -1,12 +1,12 @@ #ifndef _DAMAGERDAMAGED_H_ #define _DAMAGERDAMAGED_H_ -#include "../include/CardGui.h" +#include "../include/MTGCardInstance.h" class Player; -class DamagerDamaged:public CardGui{ - public: +struct DamagerDamaged { + MTGCardInstance* card; Player * damageSelecter; int mCount; Damage * damages[10]; @@ -18,12 +18,9 @@ class DamagerDamaged:public CardGui{ int removeDamagesFrom(DamagerDamaged * source); int sumDamages(); int hasLethalDamage(); - DamagerDamaged(CardGui * cardg, Player * _damageSelecter, bool _hasFocus); + DamagerDamaged(MTGCardInstance* card, Player * _damageSelecter, bool _hasFocus); ~DamagerDamaged(); void Render(Player * currentPlayer); - - - }; diff --git a/projects/mtg/include/DuelLayers.h b/projects/mtg/include/DuelLayers.h index d61369967..a0ed8c834 100644 --- a/projects/mtg/include/DuelLayers.h +++ b/projects/mtg/include/DuelLayers.h @@ -1,32 +1,51 @@ #ifndef _DUELLAYERS_H_ #define _DUELLAYERS_H_ - #include "GuiLayers.h" +#include "CardSelector.h" class MTGGuiHand; class MTGGuiPlay; class ActionLayer; class ActionStack; class DamageResolverLayer; +class GuiHandSelf; +class GuiHandOpponent; +class GuiCombat; +class Pos; -class DuelLayers: public GuiLayers{ +class DuelLayers { + protected: + int nbitems; + vector objects; + vector waiters; + GuiCombat* combat; + ActionLayer* action; + ActionStack* stack; + GuiHandSelf *hand; + +public: + DuelLayers(); + ~DuelLayers(); -public : ActionLayer * actionLayer(); - MTGGuiHand * handLayer(); - MTGGuiPlay * playLayer(); ActionStack * stackLayer(); - DamageResolverLayer * combatLayer(); void init(); + virtual void Update(float dt, Player * player); + void Render(); + void Add(GuiLayer * layer); + void Remove(); + int unstoppableRenderInProgress(); + int receiveEvent(WEvent * e); + float RightBoundary(); + + CardSelector* cs; }; #include "ActionLayer.h" #include "GameObserver.h" #include "MTGGamePhase.h" -#include "MTGGuiHand.h" -#include "MTGGuiPlay.h" #include "ActionStack.h" #include "Damage.h" diff --git a/projects/mtg/include/GameApp.h b/projects/mtg/include/GameApp.h index 8485b8585..c11039576 100644 --- a/projects/mtg/include/GameApp.h +++ b/projects/mtg/include/GameApp.h @@ -94,6 +94,6 @@ class GameApp: public JApp }; - +extern JQuad* manaIcons[7]; #endif diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index 9a3144678..52478c76c 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -10,6 +10,7 @@ #include "TargetChooser.h" #include "PhaseRing.h" #include "ReplacementEffects.h" +#include "GuiStatic.h" class MTGGamePhase; class MTGAbility; @@ -30,10 +31,9 @@ class GameObserver{ int currentRound; int blockersAssigned; - + public: int blockersSorted; - int forceShuffleLibrary[2]; int turn; int forceShuffleLibraries(); int targetListIsSet(MTGCardInstance * card); @@ -78,11 +78,11 @@ class GameObserver{ void untapPhase(); void draw(); int isInPlay(MTGCardInstance * card); - int isACreature(MTGCardInstance * card); + bool isCreature(MTGCardInstance * card); void Update(float dt); void Render(); - void ButtonPressed(int, PlayGuiObject*); + void ButtonPressed(PlayGuiObject*); int receiveEvent(WEvent * event); }; diff --git a/projects/mtg/include/GameOptions.h b/projects/mtg/include/GameOptions.h index fd40a6e71..f6822b0ef 100644 --- a/projects/mtg/include/GameOptions.h +++ b/projects/mtg/include/GameOptions.h @@ -6,53 +6,47 @@ using std::map; using std::string; -#define OPTIONS_MUSICVOLUME "musicVolume" -#define OPTIONS_SFXVOLUME "sfxVolume" - -#define OPTIONS_DIFFICULTY_MODE_UNLOCKED "prx_handler" //huhu -#define OPTIONS_MOMIR_MODE_UNLOCKED "prx_rimom" //haha -#define OPTIONS_EVILTWIN_MODE_UNLOCKED "prx_eviltwin" -#define OPTIONS_RANDOMDECK_MODE_UNLOCKED "prx_rnddeck" - -#define OPTIONS_DIFFICULTY "difficulty" -#define OPTIONS_CACHESIZE "cacheSize" -#define OPTIONS_PLASMAEFFECT "plasmaEffect" -#define OPTIONS_INTERRUPTMYSPELLS "interruptMySpells" -#define OPTIONS_INTERRUPTMYABILITIES "interruptMyAbilities" -#define OPTIONS_OSD "displayOSD" - -// WALDORF - added -#define OPTIONS_INTERRUPT_SECONDS "interruptSeconds" - - #define OPTIONS_SAVEFILE RESPATH"/settings/options.txt" +struct Options { + static const string MUSICVOLUME; + static const string SFXVOLUME; + static const string DIFFICULTY_MODE_UNLOCKED; + static const string MOMIR_MODE_UNLOCKED; + static const string EVILTWIN_MODE_UNLOCKED; + static const string RANDOMDECK_MODE_UNLOCKED; + static const string DIFFICULTY; + static const string CACHESIZE; + static const string PLASMAEFFECT; + static const string INTERRUPT_SECONDS; + static const string INTERRUPTMYSPELLS; + static const string INTERRUPTMYABILITIES; + static const string OSD; +}; + class GameOption { public: - int value; - string svalue; - int getIntValue(); - GameOption(int _value = 0); + int number; + string str; + GameOption(int value = 0); + GameOption(string value); }; class GameOptions { public: - map values; - static GameOptions * GetInstance(); - static void Destroy(); int save(); int load(); - static const char * phaseInterrupts[]; - - private: + static const char * phaseInterrupts[]; + GameOption& operator[](string); GameOptions(); ~GameOptions(); - static GameOptions* mInstance; + private: static map optionsTypes; - - + map values; }; +extern GameOptions options; + #endif diff --git a/projects/mtg/include/GameStateDeckViewer.h b/projects/mtg/include/GameStateDeckViewer.h index aba620025..da1a7a349 100644 --- a/projects/mtg/include/GameStateDeckViewer.h +++ b/projects/mtg/include/GameStateDeckViewer.h @@ -6,8 +6,9 @@ #include -#include "GameState.h" -#include "SimpleMenu.h" +#include "../include/GameState.h" +#include "../include/SimpleMenu.h" +#include "../include/TexturesCache.h" #include "../include/CardGui.h" #include "../include/GameOptions.h" #include "../include/PriceList.h" @@ -116,7 +117,7 @@ class GameStateDeckViewer: public GameState, public JGuiListener #if defined (WIN32) || defined (LINUX) char buf[4096]; sprintf(buf,"Loadindexes[%i] is NULL\n", i); - if(_current) sprintf(buf, "LoadIndexes[%i] : %s\n", i, _current->getName()); + if(_current) sprintf(buf, "LoadIndexes[%i] : %s\n", i, _current->getName().c_str()); OutputDebugString(buf); #endif _current = displayed_deck->getNext(_current,colorFilter); @@ -187,7 +188,7 @@ class GameStateDeckViewer: public GameState, public JGuiListener welcome_menu->Add(nbDecks+1, "--NEW--"); welcome_menu->Add(-1, "Cancel"); - if (GameApp::HasMusic && GameOptions::GetInstance()->values[OPTIONS_MUSICVOLUME].getIntValue() > 0){ + if (GameApp::HasMusic && options[Options::MUSICVOLUME].number > 0){ if (GameApp::music){ JSoundSystem::GetInstance()->StopMusic(GameApp::music); SAFE_DELETE(GameApp::music); @@ -617,7 +618,7 @@ class GameStateDeckViewer: public GameState, public JGuiListener int showName = 1; if (mParent->cache->isInCache(card) || last_user_activity > (abs(2-id) + 1)* NO_USER_ACTIVITY_SHOWCARD_DELAY){ - quad = card->getQuad(mParent->cache); + quad = cache.getQuad(card); showName = 0; } @@ -638,8 +639,8 @@ class GameStateDeckViewer: public GameState, public JGuiListener mFont->SetScale(scaleBackup); } }else{ - CardGui::alternateRender(card, mIcons, x_center, y + 142.5*scale, 0, scale); - quad = card->getThumb(); + // CardGui::alternateRender(card, mIcons, x_center, y + 142.5*scale, 0, scale); + quad = cache.getThumb(card); if (quad){ float _scale = 285 * scale / quad->mHeight; quad->SetColor(ARGB(40,255,255,255)); @@ -782,7 +783,7 @@ class GameStateDeckViewer: public GameState, public JGuiListener pricelist->setPrice(card->getMTGId(),price*2); #if defined (WIN32) || defined (LINUX) char buf[4096]; - sprintf(buf, "CARD'S NAME : %s", card->getName()); + sprintf(buf, "CARD'S NAME : %s", card->getName().c_str()); OutputDebugString(buf); #endif playerdata->collection->remove(card->getMTGId()); diff --git a/projects/mtg/include/GuiCardsController.h b/projects/mtg/include/GuiCardsController.h index abdea55df..dab6d2b7e 100644 --- a/projects/mtg/include/GuiCardsController.h +++ b/projects/mtg/include/GuiCardsController.h @@ -6,7 +6,7 @@ class GuiCardsController : public PlayGuiObjectController{ public: - GuiCardsController(int id, GameObserver* _game):PlayGuiObjectController(id, _game){}; + GuiCardsController(){}; }; diff --git a/projects/mtg/include/GuiLayers.h b/projects/mtg/include/GuiLayers.h index 1256cf378..b62bbe8fd 100644 --- a/projects/mtg/include/GuiLayers.h +++ b/projects/mtg/include/GuiLayers.h @@ -1,8 +1,6 @@ #ifndef _GUI_LAYERS_H_ #define _GUI_LAYERS_H_ -#define MAX_GUI_LAYERS 7 - #define DIR_DOWN 1 #define DIR_UP 2 #define DIR_LEFT 3 @@ -14,16 +12,13 @@ class GameObserver; class Player; - class GuiLayer{ protected: - GameObserver * game; - int mId; u32 mActionButton; public: int mCount; int mCurr; - vectormObjects; + vector mObjects; void Add(JGuiObject * object); int Remove(JGuiObject * object); int modal; @@ -32,7 +27,7 @@ class GuiLayer{ int getMaxId(); void RenderMessageBackground(float x0, float y0, float width, int height); void RenderMessageBackground(float y0, int height); - GuiLayer(int id, GameObserver* _game); + GuiLayer(); virtual ~GuiLayer(); virtual void Update(float dt); virtual bool CheckUserInput(u32 key){ return false; }; @@ -45,23 +40,8 @@ class GuiLayer{ return 1; }; - virtual int receiveEvent(WEvent * e){return 0;}; -}; - -class GuiLayers{ - protected: - int nbitems; - GuiLayer * objects[MAX_GUI_LAYERS]; - public: - GuiLayers(); - virtual void Update(float dt, Player * player); - void Render(); - void Add(GuiLayer * layer); - void Remove(); - int unstoppableRenderInProgress(); - ~GuiLayers(); - int receiveEvent(WEvent * e); - + virtual int receiveEventPlus(WEvent * e){return 0;}; + virtual int receiveEventMinus(WEvent * e){return 0;}; }; #endif diff --git a/projects/mtg/include/GuiPhaseBar.h b/projects/mtg/include/GuiPhaseBar.h index 912c5f92b..de7abd6f5 100644 --- a/projects/mtg/include/GuiPhaseBar.h +++ b/projects/mtg/include/GuiPhaseBar.h @@ -17,11 +17,11 @@ class GuiPhaseBar : public GuiLayer float angle; public: - GuiPhaseBar(GameObserver* game); + GuiPhaseBar(); ~GuiPhaseBar(); void Update(float dt); virtual void Render(); - virtual int receiveEvent(WEvent * e); + virtual int receiveEventMinus(WEvent * e); }; #endif // _GUIPHASEBAR_H_ diff --git a/projects/mtg/include/MTGCard.h b/projects/mtg/include/MTGCard.h index b574b7dfd..7f5c27e8a 100644 --- a/projects/mtg/include/MTGCard.h +++ b/projects/mtg/include/MTGCard.h @@ -10,51 +10,35 @@ #define MTG_MINIIMAGE_WIDTH 45 #define MTG_MINIIMAGE_HEIGHT 64 - #define MAX_TYPES_PER_CARD 10 - - -#include "ManaCost.h" - - -class TexturesCache; - - #include #include #include + +#include "ManaCost.h" + using namespace std; class MTGCard { protected: - - - int mtgid; ManaCost manaCost; - - char rarity; - char image_name[MTGCARD_NAME_SIZE]; - + vector ftdText; int init(); - public: - TexturesCache * mCache; string text; string name; int colors[Constants::MTG_NB_COLORS]; map basicAbilities; - vector formattedText; string magicText; int alias; string spellTargetType; - int formattedTextInit; int power; int toughness; int setId; @@ -62,11 +46,8 @@ class MTGCard { int nb_types; int types[MAX_TYPES_PER_CARD]; MTGCard(); - MTGCard(TexturesCache * cache, int set_id); + MTGCard(int set_id); MTGCard(MTGCard * source); - JQuad * getQuad(TexturesCache * cache); - JQuad * getQuad(int type=1); - JQuad * getThumb(); void setColor(int _color, int removeAllOthers = 0); int getColor(); @@ -87,13 +68,13 @@ class MTGCard { //void setImageName( char * value); char * getImageName (); - void setText( string value); + void setText(string value); const char * getText(); void addMagicText(string value); - void setName( string value); - const char * getName(); + void setName(string value); + const string getName() const; void addType(char * type_text); void addType(int id); @@ -101,22 +82,24 @@ class MTGCard { void setSubtype( string value); int removeType(string value, int removeAll = 0); int removeType(int value, int removeAll = 0); - int hasSubtype(int _subtype); - int hasSubtype(const char * _subtype); - int hasSubtype(string _subtype); - int hasType(int _type); - int hasType(const char * type); + bool hasSubtype(int _subtype); + bool hasSubtype(const char * _subtype); + bool hasSubtype(string _subtype); + bool hasType(int _type); + bool hasType(const char * type); void setManaCost(string value); ManaCost * getManaCost(); - int isACreature(); + bool isCreature(); + bool isLand(); + bool isSpell(); void setPower(int _power); int getPower(); void setToughness(int _toughness); int getToughness(); - + const vector& formattedText(); }; diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 50257cfca..97391e960 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -20,6 +20,7 @@ class ManaCost; class UntapBlockers; class CardDescriptor; class Counters; +class Pos; #include using namespace std; @@ -41,6 +42,7 @@ class MTGCardInstance: public MTGCard, public Damageable { int setDefenser(MTGCardInstance * c); int setAttacker(int value); public: + Pos* view; int regenerateTokens; bool isToken; int stillInUse(); @@ -58,7 +60,7 @@ class MTGCardInstance: public MTGCard, public Damageable { Player * owner; Counters * counters; int typeAsTarget(){return TARGET_CARD;} - const char * getDisplayName(); + const string getDisplayName(); MTGCardInstance * target; void addType(int type); @@ -94,7 +96,6 @@ class MTGCardInstance: public MTGCard, public Damageable { int regenerate(); int triggerRegenerate(); Player * controller(); - JQuad * getIcon(); ~MTGCardInstance(); int bury(); diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index cb7572f14..763238044 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -4,12 +4,6 @@ #define MTG_ERROR -1 #include "../include/MTGDefinitions.h" - - - - - - #include "../include/GameApp.h" #include "../include/TexturesCache.h" diff --git a/projects/mtg/include/MTGGameZones.h b/projects/mtg/include/MTGGameZones.h index 90a3fc5e6..d452b38ab 100644 --- a/projects/mtg/include/MTGGameZones.h +++ b/projects/mtg/include/MTGGameZones.h @@ -16,7 +16,7 @@ class Player; class MTGGameZone { protected: - + public: enum{ @@ -65,26 +65,27 @@ class MTGGameZone { }; Player * owner; - //Both cards and cardsMap contain the cards of a zone. The long term objective is to get rid of the array - vector cards; //[MTG_MAX_PLAYER_CARDS]; - map cardsMap; - int nb_cards; - MTGGameZone(); - ~MTGGameZone(); - void shuffle(); - virtual MTGCardInstance * draw(); - void addCard(MTGCardInstance * card); - void debugPrint(); - MTGCardInstance * removeCard(MTGCardInstance * card, int createCopy = 1); - MTGCardInstance * hasCard(MTGCardInstance * card); - void cleanupPhase(); - int countByType(const char * value); - int hasType(const char * value); - void setOwner(Player * player); - MTGCardInstance * lastCardDrawn; - static MTGGameZone * stringToZone(string zoneName, MTGCardInstance * source, MTGCardInstance * target); - static int zoneStringToId(string zoneName); - static MTGGameZone *intToZone(int zoneId, MTGCardInstance * source = NULL,MTGCardInstance * target = NULL); + //Both cards and cardsMap contain the cards of a zone. The long term objective is to get rid of the array + vector cards; //[MTG_MAX_PLAYER_CARDS]; + map cardsMap; + int nb_cards; + MTGGameZone(); + ~MTGGameZone(); + void shuffle(); + virtual MTGCardInstance * draw(); + void addCard(MTGCardInstance * card); + void debugPrint(); + MTGCardInstance * removeCard(MTGCardInstance * card, int createCopy = 1); + MTGCardInstance * hasCard(MTGCardInstance * card); + void cleanupPhase(); + int countByType(const char * value); + int hasType(const char * value); + void setOwner(Player * player); + MTGCardInstance * lastCardDrawn; + static MTGGameZone * stringToZone(string zoneName, MTGCardInstance * source, MTGCardInstance * target); + static int zoneStringToId(string zoneName); + static MTGGameZone *intToZone(int zoneId, MTGCardInstance * source = NULL,MTGCardInstance * target = NULL); + bool needShuffle; }; class MTGLibrary: public MTGGameZone { diff --git a/projects/mtg/include/MTGGuiHand.h b/projects/mtg/include/MTGGuiHand.h index 43545f8df..fd350ef6d 100644 --- a/projects/mtg/include/MTGGuiHand.h +++ b/projects/mtg/include/MTGGuiHand.h @@ -17,17 +17,18 @@ class GuiCardscontroller; class MTGGuiHand: public GuiCardsController{ protected: + GameObserver* game; int currentId[2]; Player * currentPlayer; int mShowHand; float mAnimState; JLBFont * mFont; public: - MTGGuiHand(int id, GameObserver * _game); + MTGGuiHand(GameObserver*); void Update(float dt); bool CheckUserInput(u32 key); virtual void Render(); - void updateCards(); + void updateCards(); void showHand (bool show);// WALDORF - added }; diff --git a/projects/mtg/include/MTGGuiPlay.h b/projects/mtg/include/MTGGuiPlay.h index e96cb23c3..82b41164e 100644 --- a/projects/mtg/include/MTGGuiPlay.h +++ b/projects/mtg/include/MTGGuiPlay.h @@ -12,6 +12,7 @@ class CardGui; class MTGGuiPlay: public PlayGuiObjectController { protected: + GameObserver* game; int offset; Player * currentPlayer; MTGCardInstance * cardsGrid[SCREEN_WIDTH/5][SCREEN_HEIGHT/5]; @@ -43,14 +44,14 @@ class MTGGuiPlay: public PlayGuiObjectController { void adjustCardPosition(CardGui * cardg); public: CardGui * getByCard(MTGCardInstance * card); - MTGGuiPlay(int id, GameObserver * game); + MTGGuiPlay(GameObserver * game); ~MTGGuiPlay(); void Update(float dt); bool CheckUserInput(u32 key); virtual void Render(); void forceUpdateCards(); void updateCards(); - int receiveEvent(WEvent * e); + int receiveEventPlus(WEvent * e); }; diff --git a/projects/mtg/include/PhaseRing.h b/projects/mtg/include/PhaseRing.h index 8a2f6fbbb..7a111d0c3 100644 --- a/projects/mtg/include/PhaseRing.h +++ b/projects/mtg/include/PhaseRing.h @@ -14,7 +14,7 @@ class Phase{ public: int id; Player * player; - Phase(int _id, Player * _player):id(_id),player(_player){}; + Phase(int id, Player *player):id(id),player(player){}; }; class PhaseRing{ diff --git a/projects/mtg/include/PlayGuiObject.h b/projects/mtg/include/PlayGuiObject.h index 40e97c39b..3f1d19dc4 100644 --- a/projects/mtg/include/PlayGuiObject.h +++ b/projects/mtg/include/PlayGuiObject.h @@ -11,12 +11,11 @@ #define GUI_LIBRARY 4 #include +#include "Effects.h" +#include "WEvent.h" +#include "Pos.h" -class MTGGameZone; -class Player; -class CardDisplay; - -class PlayGuiObject: public JGuiObject, public JGuiListener{ +class PlayGuiObject: public JGuiObject, public JGuiListener, public Pos{ protected: public: @@ -24,59 +23,17 @@ class PlayGuiObject: public JGuiObject, public JGuiListener{ float mHeight; float defaultHeight; bool mHasFocus; - int x; - int y; int type; virtual void Entering(){mHasFocus = true;}; virtual bool Leaving(u32 key){mHasFocus = false;return true;}; virtual bool ButtonPressed(){return true;}; - virtual void Render(){}; + virtual void Render(); virtual void Update(float dt); - PlayGuiObject(int id, float desiredHeight,float _x, float _y, bool hasFocus); + PlayGuiObject(float desiredHeight, float x, float y, bool hasFocus); + PlayGuiObject(float desiredHeight, const Pos& ref, bool hasFocus); virtual void ButtonPressed(int controllerId, int controlId){}; virtual ~PlayGuiObject(){}; - + vector effects; }; -class GuiAvatar: public PlayGuiObject{ - protected: - - int avatarRed; - int currentLife; - public: - Player * player; - virtual void Render(); - GuiAvatar(int id, float desiredHeight,float _x, float _y, bool hasFocus,Player * _player); - virtual ostream& toString(ostream& out) const; -}; - -class GuiGameZone: public PlayGuiObject{ - protected: - MTGGameZone * zone; - - public: - CardDisplay * cd; - int showCards; - virtual void Render(); - virtual void Update(float dt); - GuiGameZone(int id, float desiredHeight,float _x, float _y, bool hasFocus,MTGGameZone * _zone); - ~GuiGameZone(); - virtual void ButtonPressed(int controllerId, int controlId); - void toggleDisplay(); - virtual ostream& toString(ostream& out) const; -}; - -class GuiGraveyard: public GuiGameZone{ - public: - GuiGraveyard(int id, float desiredHeight,float _x, float _y, bool hasFocus,Player * player); - virtual ostream& toString(ostream& out) const; -}; - -class GuiLibrary: public GuiGameZone{ - public: - GuiLibrary(int id, float desiredHeight,float _x, float _y, bool hasFocus,Player * player); - virtual ostream& toString(ostream& out) const; -}; - - #endif diff --git a/projects/mtg/include/PlayGuiObjectController.h b/projects/mtg/include/PlayGuiObjectController.h index 9429160cf..11ccbb971 100644 --- a/projects/mtg/include/PlayGuiObjectController.h +++ b/projects/mtg/include/PlayGuiObjectController.h @@ -14,7 +14,7 @@ class PlayGuiObjectController : public GuiLayer{ public: virtual void Update(float dt); virtual bool CheckUserInput(u32 key); - PlayGuiObjectController(int id, GameObserver* _game):GuiLayer(id, _game){last_user_move=0;}; + PlayGuiObjectController(){last_user_move=0;}; virtual void Render(){GuiLayer::Render();}; }; diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 23dc832a4..07768168e 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -17,14 +17,14 @@ class Player: public Damageable{ public: virtual void End(); int typeAsTarget(){return TARGET_PLAYER;} - const char * getDisplayName(); + const string getDisplayName(); virtual int displayStack(){return 1;} JTexture * mAvatarTex; JQuad * mAvatar; int canPutLandsIntoPlay; MTGPlayerCards * game; int afterDamage(); - Player(MTGPlayerCards * _deck, string deckFile, string deckFileSmall); + Player(MTGPlayerCards * deck, string deckFile, string deckFileSmall); virtual ~Player(); void unTapPhase(); MTGInPlay * inPlay(); @@ -41,7 +41,7 @@ class Player: public Damageable{ class HumanPlayer: public Player{ public: - HumanPlayer(MTGPlayerCards * _deck, char * _deckFile, string _deckFileSmall); + HumanPlayer(MTGPlayerCards * deck, string deckFile, string deckFileSmall); }; diff --git a/projects/mtg/include/TargetChooser.h b/projects/mtg/include/TargetChooser.h index 27b76ca3c..aa4d21675 100644 --- a/projects/mtg/include/TargetChooser.h +++ b/projects/mtg/include/TargetChooser.h @@ -37,14 +37,14 @@ class TargetChooser: public TargetsList { TargetChooser(MTGCardInstance * card = NULL, int _maxtargets = -1); - MTGCardInstance * source; + MTGCardInstance * source; MTGCardInstance * targetter; //Optional, usually equals source, used for protection from... int maxtargets; //Set to -1 for "unlimited" virtual int targetsZone(MTGGameZone * z){return 0;}; int ForceTargetListReady(); int targetsReadyCheck(); virtual int addTarget(Targetable * target); - virtual int canTarget(Targetable * _target); + virtual bool canTarget(Targetable * _target); virtual int full(){if (maxtargets != -1 && cursor>=maxtargets) {return 1;} else{return 0;}}; virtual int ready(){return cursor;}; virtual ~TargetChooser(){}; @@ -61,7 +61,6 @@ class TargetChooserFactory{ }; - class TargetZoneChooser:public TargetChooser{ public: int zones[10]; @@ -70,16 +69,15 @@ class TargetZoneChooser:public TargetChooser{ int targetsZone(MTGGameZone * z); TargetZoneChooser(MTGCardInstance * card = NULL, int _maxtargets = 1); TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1); - virtual int canTarget(Targetable * _card); + virtual bool canTarget(Targetable * _card); }; class CardTargetChooser:public TargetZoneChooser { - protected: MTGCardInstance * validTarget; public: - CardTargetChooser(MTGCardInstance * _card, MTGCardInstance * source,int * _zones = NULL, int _nbzones = 0); - virtual int canTarget(Targetable * target ); + CardTargetChooser(MTGCardInstance * card, MTGCardInstance * source, int * zones = NULL, int nbzones = 0); + virtual bool canTarget(Targetable * target); }; @@ -89,7 +87,7 @@ class CreatureTargetChooser:public TargetZoneChooser{ int maxtoughness; CreatureTargetChooser(int * _zones, int _nbzones,MTGCardInstance * card = NULL, int _maxtargets = 1); CreatureTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1); - virtual int canTarget(Targetable * _card); + virtual bool canTarget(Targetable * _card); }; @@ -98,7 +96,7 @@ class DamageableTargetChooser:public CreatureTargetChooser{ public: DamageableTargetChooser(int * _zones, int _nbzones,MTGCardInstance * card = NULL, int _maxtargets = 1):CreatureTargetChooser( _zones,_nbzones, card, _maxtargets){}; DamageableTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1):CreatureTargetChooser(card, _maxtargets){}; - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; @@ -107,7 +105,7 @@ protected: Player * p; //In Case we can only target a specific player public: PlayerTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, Player *_p = NULL); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; class TypeTargetChooser:public TargetZoneChooser{ @@ -118,7 +116,7 @@ class TypeTargetChooser:public TargetZoneChooser{ TypeTargetChooser(const char * _type, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1); void addType(int type); void addType(const char * type); - virtual int canTarget(Targetable * targe); + virtual bool canTarget(Targetable * targe); }; class DescriptorTargetChooser:public TargetZoneChooser{ @@ -126,7 +124,7 @@ class DescriptorTargetChooser:public TargetZoneChooser{ CardDescriptor * cd; DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card = NULL, int _maxtargets = 1); DescriptorTargetChooser(CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); ~DescriptorTargetChooser(); }; @@ -135,14 +133,14 @@ class SpellTargetChooser:public TargetChooser{ public: int color; SpellTargetChooser( MTGCardInstance * card = NULL,int _color = -1, int _maxtargets = 1 ); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; class SpellOrPermanentTargetChooser:public TargetZoneChooser{ public: int color; SpellOrPermanentTargetChooser(MTGCardInstance * card = NULL,int _color = -1 , int _maxtargets = 1); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; @@ -152,13 +150,13 @@ class DamageTargetChooser:public TargetChooser{ int color; int state; DamageTargetChooser( MTGCardInstance * card = NULL,int _color = -1 , int _maxtargets = 1, int state = NOT_RESOLVED); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; class DamageOrPermanentTargetChooser:public TargetZoneChooser{ public: int color; DamageOrPermanentTargetChooser(MTGCardInstance * card = NULL,int _color = -1 , int _maxtargets = 1); - virtual int canTarget(Targetable * target); + virtual bool canTarget(Targetable * target); }; #endif diff --git a/projects/mtg/include/Targetable.h b/projects/mtg/include/Targetable.h index f55446793..866d1eef1 100644 --- a/projects/mtg/include/Targetable.h +++ b/projects/mtg/include/Targetable.h @@ -8,7 +8,7 @@ class Targetable{ public: virtual int typeAsTarget() = 0; - virtual const char * getDisplayName() =0; + virtual const string getDisplayName() = 0; }; #endif diff --git a/projects/mtg/include/TexturesCache.h b/projects/mtg/include/TexturesCache.h index 0a91c5305..e68e63d14 100644 --- a/projects/mtg/include/TexturesCache.h +++ b/projects/mtg/include/TexturesCache.h @@ -43,7 +43,6 @@ class TexturesCache{ int nb_textures; int delete_previous; int totalsize; - int maxSize; CardTexture * cache[MAX_CACHE_OBJECTS]; public: int isInCache(MTGCard * card, int type=CACHE_CARD); @@ -55,8 +54,8 @@ class TexturesCache{ int getCacheById(int id, int type=CACHE_CARD); JQuad * getQuad(MTGCard * card, int type=CACHE_CARD); JQuad * getThumb(MTGCard * card){return getQuad(card, CACHE_THUMB);}; - }; +extern TexturesCache cache; class SampleCached{ diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index 0f6b9de91..e393277fd 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -1,96 +1,100 @@ -#ifndef _WEVENT_H_ -#define _WEVENT_H_ - -class MTGCardInstance; -class MTGGameZone; -class Damage; -class Phase; -class Targetable; - -class WEvent{ -public: - enum{ - NOT_SPECIFIED = 0, - CHANGE_ZONE = 1, - DAMAGE = 2, - CHANGE_PHASE = 3, - }; - int type; //Deprecated, use dynamic casting instead - WEvent(int _type = NOT_SPECIFIED); - virtual ~WEvent() {}; -}; - -class WEventZoneChange: public WEvent{ -public: - MTGCardInstance * card; - MTGGameZone * from; - MTGGameZone * to; - WEventZoneChange(MTGCardInstance * _card, MTGGameZone * _from, MTGGameZone *_to); - virtual ~WEventZoneChange() {}; -}; - - -class WEventDamage: public WEvent{ -public: - Damage * damage; - WEventDamage(Damage * _damage); -}; - -class WEventPhaseChange: public WEvent{ -public: - Phase * from; - Phase * to; - WEventPhaseChange(Phase * _from, Phase * _to); -}; - - -//Abstract class of event when a card's status changes -class WEventCardUpdate: public WEvent{ -public: - MTGCardInstance * card; - WEventCardUpdate(MTGCardInstance * card):WEvent(),card(card){}; -}; - -//Event when a card is tapped/untapped -class WEventCardTap: public WEventCardUpdate{ -public: - bool before; - bool after; - WEventCardTap(MTGCardInstance * card, bool before, bool after); -}; - -//Event when a card's "attacker" status changes -//before:Player/Planeswalker that card was attacking previously -//after: Player/Planeswalker that card is attacking now -class WEventCreatureAttacker: public WEventCardUpdate{ -public: - Targetable * before; - Targetable * after; - WEventCreatureAttacker(MTGCardInstance * card,Targetable * from, Targetable * to); - -}; - -//Event when a card's "defenser" status changes -//before : attacker that card was blocking previously -//after: attacker that card is blocking now -class WEventCreatureBlocker: public WEventCardUpdate{ -public: - MTGCardInstance * before; - MTGCardInstance * after; - WEventCreatureBlocker(MTGCardInstance * card,MTGCardInstance * from,MTGCardInstance * to); - -}; - -//Event when a blocker is reordered -//exchangeWith: exchange card's position with exchangeWith's position -//attacker:both card and exchangeWith *should* be in attacker's "blockers" list. -class WEventCreatureBlockerRank: public WEventCardUpdate{ -public: - MTGCardInstance * exchangeWith; - MTGCardInstance * attacker; - WEventCreatureBlockerRank(MTGCardInstance * card,MTGCardInstance * exchangeWith, MTGCardInstance * attacker); - -}; - - -#endif +#ifndef _WEVENT_H_ +#define _WEVENT_H_ + +class MTGCardInstance; +class MTGGameZone; +class Damage; +class Phase; +class Targetable; + +class WEvent{ +public: + enum{ + NOT_SPECIFIED = 0, + CHANGE_ZONE = 1, + DAMAGE = 2, + CHANGE_PHASE = 3, + }; + int type; //Deprecated, use dynamic casting instead + WEvent(int type = NOT_SPECIFIED); + virtual ~WEvent() {}; +}; + +struct WEventZoneChange: public WEvent{ + MTGCardInstance * card; + MTGGameZone * from; + MTGGameZone * to; + WEventZoneChange(MTGCardInstance * card, MTGGameZone * from, MTGGameZone *to); + virtual ~WEventZoneChange() {}; +}; + + +struct WEventDamage: public WEvent{ + Damage * damage; + WEventDamage(Damage * damage); +}; + +struct WEventPhaseChange: public WEvent{ + Phase * from; + Phase * to; + WEventPhaseChange(Phase * from, Phase * to); +}; + + +//Abstract class of event when a card's status changes +struct WEventCardUpdate: public WEvent{ + MTGCardInstance * card; + WEventCardUpdate(MTGCardInstance * card); +}; + +//Event when a card is tapped/untapped +struct WEventCardTap: public WEventCardUpdate{ + bool before; + bool after; + WEventCardTap(MTGCardInstance * card, bool before, bool after); +}; + +//Event when a card's "attacker" status changes +//before:Player/Planeswalker that card was attacking previously +//after: Player/Planeswalker that card is attacking now +struct WEventCreatureAttacker: public WEventCardUpdate{ + Targetable * before; + Targetable * after; + WEventCreatureAttacker(MTGCardInstance * card, Targetable * from, Targetable * to); +}; + +//Event when a card's "defenser" status changes +//before : attacker that card was blocking previously +//after: attacker that card is blocking now +struct WEventCreatureBlocker: public WEventCardUpdate{ + MTGCardInstance * before; + MTGCardInstance * after; + WEventCreatureBlocker(MTGCardInstance * card,MTGCardInstance * from,MTGCardInstance * to); +}; + +//Event when a blocker is reordered +//exchangeWith: exchange card's position with exchangeWith's position +//attacker:both card and exchangeWith *should* be in attacker's "blockers" list. +struct WEventCreatureBlockerRank: public WEventCardUpdate{ + MTGCardInstance * exchangeWith; + MTGCardInstance * attacker; + WEventCreatureBlockerRank(MTGCardInstance * card,MTGCardInstance * exchangeWith, MTGCardInstance * attacker); + +}; + +//Event when a mana is engaged +//color : color +struct WEventEngageMana : public WEvent { + int color; + MTGCardInstance* card; + WEventEngageMana(int color, MTGCardInstance* card); +}; + +//Event when a mana is consumed +//color : color +struct WEventConsumeMana : public WEvent { + int color; + WEventConsumeMana(int color); +}; + +#endif diff --git a/projects/mtg/include/config.h b/projects/mtg/include/config.h index 2eedd16b7..36e1ae94c 100644 --- a/projects/mtg/include/config.h +++ b/projects/mtg/include/config.h @@ -26,4 +26,11 @@ #define RESPATH "Res" #endif +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + #endif diff --git a/projects/mtg/src/AIMomirPlayer.cpp b/projects/mtg/src/AIMomirPlayer.cpp index 45916fc4e..79d8a9713 100644 --- a/projects/mtg/src/AIMomirPlayer.cpp +++ b/projects/mtg/src/AIMomirPlayer.cpp @@ -9,7 +9,7 @@ MTGAbility * AIMomirPlayer::momirAbility = NULL; -AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * _deck, char * file, const char * fileSmall, char * avatarFile): AIPlayerBaka(_deck,file, fileSmall, avatarFile){ +AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * deck, string file, string fileSmall, string avatarFile) : AIPlayerBaka(deck, file, fileSmall, avatarFile) { momirAbility = NULL; agressivity = 100; } diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 30c6eab12..ec4cb6ef2 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -1,766 +1,767 @@ -#include "../include/config.h" -#include "../include/AIPlayer.h" -#include "../include/CardDescriptor.h" -#include "../include/DamageResolverLayer.h" -#include "../include/DamagerDamaged.h" -#include "../include/AIStats.h" -#include "../include/AllAbilities.h" -#include "../include/ExtraCost.h" - -const char * const MTG_LAND_TEXTS[] = {"artifact","forest","island","mountain","swamp","plains","other lands"}; - -int AIAction::Act(){ - GameObserver * g = GameObserver::GetInstance(); - if (player){ - g->cardClick(NULL, player); - return 1; - } - if (ability){ - g->mLayers->actionLayer()->reactToClick(ability,click); - if (target) g->cardClick(target); - return 1; - }else if (click){ //Shouldn't be used, really... - g->cardClick(click); - if (target) g->cardClick(target); - return 1; - } - return 0; -} - -AIPlayer::AIPlayer(MTGPlayerCards * _deck, string file, string fileSmall): Player(_deck, file, fileSmall){ - potentialMana = NEW ManaCost(); - nextCardToPlay = NULL; - stats = NULL; - agressivity = 50; -} - -AIPlayer::~AIPlayer(){ - SAFE_DELETE(potentialMana); - if (stats){ - stats->save(); - SAFE_DELETE(stats); - } - //TODO delete clickstream! -} -MTGCardInstance * AIPlayer::chooseCard(TargetChooser * tc, MTGCardInstance * source, int random){ - for (int i = 0; i < game->hand->nb_cards; i++){ - MTGCardInstance * card = game->hand->cards[i]; - if (!tc->alreadyHasTarget(card) && tc->canTarget(card)){ - return card; - } - } - return NULL; -} - -int AIPlayer::Act(float dt){ - GameObserver * gameObs = GameObserver::GetInstance(); - if (gameObs->currentPlayer == this){ - gameObs->userRequestNextGamePhase(); - return 1; - }else{ - return 1; - } -} - - -void AIPlayer::tapLandsForMana(ManaCost * potentialMana, ManaCost * cost){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("tapping land for mana\n"); -#endif - if (!cost) return; - ManaCost * diff = potentialMana->Diff(cost); - GameObserver * g = GameObserver::GetInstance(); - - mapused; - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish - //Make sure we can use the ability - MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); +#include "../include/config.h" +#include "../include/AIPlayer.h" +#include "../include/CardDescriptor.h" +#include "../include/DamageResolverLayer.h" +#include "../include/DamagerDamaged.h" +#include "../include/AIStats.h" +#include "../include/AllAbilities.h" +#include "../include/ExtraCost.h" + +const char * const MTG_LAND_TEXTS[] = {"artifact","forest","island","mountain","swamp","plains","other lands"}; + +int AIAction::Act(){ + GameObserver * g = GameObserver::GetInstance(); + if (player){ + g->cardClick(NULL, player); + return 1; + } + if (ability){ + g->mLayers->actionLayer()->reactToClick(ability,click); + if (target) g->cardClick(target); + return 1; + }else if (click){ //Shouldn't be used, really... + g->cardClick(click); + if (target) g->cardClick(target); + return 1; + } + return 0; +} + +AIPlayer::AIPlayer(MTGPlayerCards * deck, string file, string fileSmall) : Player(deck, file, fileSmall) { + potentialMana = NEW ManaCost(); + nextCardToPlay = NULL; + stats = NULL; + agressivity = 50; +} + +AIPlayer::~AIPlayer(){ + SAFE_DELETE(potentialMana); + if (stats){ + stats->save(); + SAFE_DELETE(stats); + } + //TODO delete clickstream! +} +MTGCardInstance * AIPlayer::chooseCard(TargetChooser * tc, MTGCardInstance * source, int random){ + for (int i = 0; i < game->hand->nb_cards; i++){ + MTGCardInstance * card = game->hand->cards[i]; + if (!tc->alreadyHasTarget(card) && tc->canTarget(card)){ + return card; + } + } + return NULL; +} + +int AIPlayer::Act(float dt){ + GameObserver * gameObs = GameObserver::GetInstance(); + if (gameObs->currentPlayer == this){ + gameObs->userRequestNextGamePhase(); + return 1; + }else{ + return 1; + } +} + + +void AIPlayer::tapLandsForMana(ManaCost * potentialMana, ManaCost * cost){ +#if defined (WIN32) || defined (LINUX) + OutputDebugString("tapping land for mana\n"); +#endif + if (!cost) return; + ManaCost * diff = potentialMana->Diff(cost); + GameObserver * g = GameObserver::GetInstance(); + + mapused; + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish + //Make sure we can use the ability + MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); AManaProducer * amp = dynamic_cast(a); - if (amp && canHandleCost(amp)){ - MTGCardInstance * card = amp->source; - if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost()==1){ - used[card] = true; - int doTap = 1; - for (int i=Constants::MTG_NB_COLORS-1; i>= 0; i--){ - if (diff->getCost(i) && amp->output->getCost(i) ){ - diff->remove(i,1); - doTap = 0; - break; - } - } - if (doTap){ - AIAction * action = NEW AIAction(amp,card); - clickstream.push(action); - } - } - } - } - delete(diff); - -} - -ManaCost * AIPlayer::getPotentialMana(){ - SAFE_DELETE(potentialMana); - potentialMana = NEW ManaCost(); - GameObserver * g = GameObserver::GetInstance(); - mapused; - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish - //Make sure we can use the ability - MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); + if (amp && canHandleCost(amp)){ + MTGCardInstance * card = amp->source; + if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost()==1){ + used[card] = true; + int doTap = 1; + for (int i=Constants::MTG_NB_COLORS-1; i>= 0; i--){ + if (diff->getCost(i) && amp->output->getCost(i) ){ + diff->remove(i,1); + doTap = 0; + break; + } + } + if (doTap){ + AIAction * action = NEW AIAction(amp,card); + clickstream.push(action); + } + } + } + } + delete(diff); + +} + +ManaCost * AIPlayer::getPotentialMana(){ + SAFE_DELETE(potentialMana); + potentialMana = NEW ManaCost(); + GameObserver * g = GameObserver::GetInstance(); + mapused; + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish + //Make sure we can use the ability + MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); AManaProducer * amp = dynamic_cast(a); - if (amp && canHandleCost(amp)){ - MTGCardInstance * card = amp->source; - if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost()==1){ - potentialMana->add(amp->output); - used[card] = true; - } - } - } - - return potentialMana; -} - - -int AIPlayer::getEfficiency(AIAction * action){ - return action->getEfficiency(); -} - -int AIPlayer::canHandleCost(MTGAbility * ability){ - //Can't handle sacrifice costs that require a target yet :( - if (ability->cost){ - ExtraCosts * ec = ability->cost->extraCosts; - if (ec){ - for (size_t i = 0; i < ec->costs.size(); i++){ - if (ec->costs[i]->tc) return 0; - } - } - } - return 1; -} - -int AIAction::getEfficiency(){ - //TODO add multiplier according to what the player wants - if (efficiency != -1) return efficiency; - if (!ability) return 0; - GameObserver * g = GameObserver::GetInstance(); - ActionStack * s = g->mLayers->stackLayer(); - Player * p = g->currentlyActing(); - if (s->has(ability)) return 0; - - MTGAbility * a = ability; - GenericTargetAbility * gta = dynamic_cast(a); - if (gta) a = gta->ability; - - GenericActivatedAbility * gaa = dynamic_cast(a); - if (gaa) a = gaa->ability; - - if (!a){ - OutputDebugString("FATAL: Ability is NULL in AIAction::getEfficiency()"); - return 0; - } - - if (!((AIPlayer *)p)->canHandleCost(ability)) return 0; - - switch (a->aType){ - case MTGAbility::DAMAGER: - { - AADamager * aad = (AADamager *) a; - if ( p == target->controller()){ - efficiency = 0; - }else if (aad->damage >= target->toughness){ - efficiency = 100; - }else if (target->toughness){ - efficiency = (50 * aad->damage) / target->toughness; - }else{ - efficiency = 0; - } - break; - } - case MTGAbility::STANDARD_REGENERATE: - { - MTGCardInstance * _target = (MTGCardInstance *)(a->target); - efficiency = 0; - if (!_target->regenerateTokens && g->getCurrentGamePhase()< Constants::MTG_PHASE_COMBATDAMAGE && (_target->defenser || _target->blockers.size())){ - efficiency = 95; - } - //TODO If the card is the target of a damage spell - break; - } - case MTGAbility::MANA_PRODUCER: //can't use mana producers right now :/ - efficiency = 0; - break; - default: - if (target){ - efficiency = rand() % 5; //Small percentage of chance for other abilities - }else{ - efficiency = rand() % 10; - } - break; - } - return efficiency; -} - - - - -int AIPlayer::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, map * ranking){ - if (!a->tc){ - AIAction * as = NEW AIAction(a,c,NULL); - (*ranking)[as] = 1; - return 1; - } - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2; i++){ - Player * p = g->players[i]; - MTGGameZone * playerZones[] = {p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay}; - for (int j = 0; j < 4; j++){ - MTGGameZone * zone = playerZones[j]; - for (int k=0; k < zone->nb_cards; k++){ - MTGCardInstance * t = zone->cards[k]; - if (a->tc->canTarget(t)){ - - AIAction * as = NEW AIAction(a,c,t); - (*ranking)[as] = 1; - } - } - } - } - return 1; -} - -int AIPlayer::selectAbility(){ - mapranking; - list::iterator it; - ManaCost * pMana = getPotentialMana(); - GameObserver * g = GameObserver::GetInstance(); - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish - //Make sure we can use the ability - MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); - for (int j=0; j < game->inPlay->nb_cards; j++){ - MTGCardInstance * card = game->inPlay->cards[j]; - if (a->isReactingToClick(card,pMana)){ - createAbilityTargets(a, card, &ranking); - } - } - } - - if (ranking.size()){ - OutputDebugString("We have a winner\n"); - AIAction * a = ranking.begin()->first; - int chance = 1 + rand() % 100; - if (getEfficiency(a) < chance){ - a = NULL; - }else{ -OutputDebugString("We REALLY have a winner\n"); - tapLandsForMana(pMana, a->ability->cost); - clickstream.push(a); - } - map::iterator it2; - for (it2 = ranking.begin(); it2!=ranking.end(); it2++){ - if (a != it2->first) delete(it2->first); - } - } - return 1; -} - - - -int AIPlayer::interruptIfICan(){ - GameObserver * g = GameObserver::GetInstance(); - - if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this){ - if (!clickstream.empty()) g->mLayers->stackLayer()->cancelInterruptOffer(); - else g->mLayers->stackLayer()->setIsInterrupting(this); - return 1; - } - return 0; -} - -int AIPlayer::effectBadOrGood(MTGCardInstance * card){ - int id = card->getMTGId(); - AbilityFactory * af = NEW AbilityFactory(); - int autoGuess = af->magicText(id,NULL,card); - delete af; - if (autoGuess) return autoGuess; - return BAKA_EFFECT_DONTKNOW; -} - - - -int AIPlayer::chooseTarget(TargetChooser * tc){ - Targetable * potentialTargets[50]; - int nbtargets = 0; - GameObserver * gameObs = GameObserver::GetInstance(); - int checkOnly = 0; - if (tc){ - checkOnly = 1; - }else{ - tc = gameObs->getCurrentTargetChooser(); - } - if (!tc) return 0; - if (!(gameObs->currentlyActing() == this)) return 0; - Player * target = this; - int cardEffect = effectBadOrGood(tc->source); - if (cardEffect != BAKA_EFFECT_GOOD){ - target = this->opponent(); - } - - - if (!tc->alreadyHasTarget(target) && tc->canTarget(target) && nbtargets < 50){ - for (int i = 0; i < 3; i++){ //Increase probability to target a player when this is possible - potentialTargets[nbtargets] = target; - nbtargets++; - } - if (checkOnly) return 1; - } - MTGPlayerCards * playerZones = target->game; - MTGGameZone * zones[] = {playerZones->hand,playerZones->library,playerZones->inPlay, playerZones->graveyard}; - for (int j = 0; j < 4; j++){ - MTGGameZone * zone = zones[j]; - for (int k=0; k< zone->nb_cards; k++){ - MTGCardInstance * card = zone->cards[k]; - if (!tc->alreadyHasTarget(card) && tc->canTarget(card) && nbtargets < 50){ - if (checkOnly) return 1; - int multiplier = 1; - if (getStats() && getStats()->isInTop(card,10)){ - multiplier++; - if (getStats()->isInTop(card,5)){ - multiplier++; - if (getStats()->isInTop(card,3)){ - multiplier++; - } - } - } - for (int l=0; l < multiplier; l++){ - potentialTargets[nbtargets] = card; - nbtargets++; - } - } - } - } - if (nbtargets){ - int i = rand() % nbtargets; - int type = potentialTargets[i]->typeAsTarget(); - switch(type){ - case TARGET_CARD: - { - MTGCardInstance * card = ((MTGCardInstance *) potentialTargets[i]); - clickstream.push(NEW AIAction(card)); - return 1; - break; - } - case TARGET_PLAYER: - { - Player * player = ((Player *) potentialTargets[i]); - clickstream.push(NEW AIAction(player)); - return 1; - break; - } - } - } - //BIG PROBLEM - gameObs->cancelCurrentAction(); - return 0; -} - -int AIPlayer::getCreaturesInfo(Player * player, int neededInfo , int untapMode, int canAttack){ - int result = 0; - CardDescriptor cd; - cd.init(); - cd.setType("Creature"); - cd.unsecureSetTapped(untapMode); - MTGCardInstance * card = NULL; - while((card = cd.nextmatch(player->game->inPlay, card))){ - if (!canAttack || card->canAttack()){ - if (neededInfo == INFO_NBCREATURES){ - result++; - }else{ - result+=card->power; - } - } - } - return result; -} - - - -int AIPlayer::chooseAttackers(){ - //Attack with all creatures - //How much damage can the other player do during his next Attack ? - int opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER); - int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES); - int myForce = getCreaturesInfo(this,INFO_CREATURESPOWER,-1,1); - int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1,1); - bool attack = ((myCreatures > opponentCreatures) || (myForce > opponentForce) || (myForce > 2*opponent()->life)); - if (agressivity > 80 && !attack && life > opponentForce) { - opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES,-1); - opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER,-1); - attack = (myCreatures >= opponentCreatures && myForce > opponentForce) || (myForce > opponentForce) || (myForce > opponent()->life); - } - printf("Choose attackers : %i %i %i %i -> %i\n", opponentForce, opponentCreatures, myForce, myCreatures, attack); - if (attack){ - CardDescriptor cd; - cd.init(); - cd.setType("creature"); - MTGCardInstance * card = NULL; - GameObserver * g = GameObserver::GetInstance(); - MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_ATTACK_RULE); - while((card = cd.nextmatch(game->inPlay, card))){ - g->mLayers->actionLayer()->reactToClick(a,card); - } - } - return 1; -} - -/* Can I first strike my oponent and get away with murder ? */ -int AIPlayer::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy){ - if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) return 0; - if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) return 0; - if (!(card->power >= ennemy->toughness)) return 0; - return 1; -} - -int AIPlayer::chooseBlockers(){ - map opponentsToughness; - int opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER); - //int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); - //int myForce = getCreaturesInfo(this,INFO_CREATURESPOWER); - //int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1); - CardDescriptor cd; - cd.init(); - cd.setType("Creature"); - cd.unsecureSetTapped(-1); - MTGCardInstance * card = NULL; - GameObserver * g = GameObserver::GetInstance(); - MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_BLOCK_RULE); - - while((card = cd.nextmatch(game->inPlay, card))){ - g->mLayers->actionLayer()->reactToClick(a,card); - int set = 0; - while(!set){ - if (!card->defenser){ - set = 1; - }else{ - MTGCardInstance * attacker = card->defenser; - map::iterator it = opponentsToughness.find(attacker); - if ( it == opponentsToughness.end()){ - opponentsToughness[attacker] = attacker->toughness; - it = opponentsToughness.find(attacker); - } - if (opponentsToughness[attacker] > 0 && getStats() && getStats()->isInTop(attacker,3,false)){ - opponentsToughness[attacker]-= card->power; - set = 1; - }else{ - g->mLayers->actionLayer()->reactToClick(a,card); - } - } - } - } - card = NULL; - while((card = cd.nextmatch(game->inPlay, card))){ - if (card->defenser && opponentsToughness[card->defenser] > 0){ - while (card->defenser){ - - g->mLayers->actionLayer()->reactToClick(a,card); - } - } - } - card = NULL; - while((card = cd.nextmatch(game->inPlay, card))){ - if(!card->defenser){ - g->mLayers->actionLayer()->reactToClick(a,card); - int set = 0; - while(!set){ - if (!card->defenser){ - set = 1; - }else{ - MTGCardInstance * attacker = card->defenser; - if (opponentsToughness[attacker] <= 0 || - (card->toughness <= attacker->power && opponentForce*2 nbOpponents()>1){ - g->mLayers->actionLayer()->reactToClick(a,card); - }else{ - set = 1; - } - } - } - } - } - return 1; -} - -int AIPlayer::orderBlockers(){ - GameObserver * g = GameObserver::GetInstance(); - DamageResolverLayer * drl = g->mLayers->combatLayer(); - if (drl->orderingIsNeeded && g->currentPlayer==this){ - drl->blockersOrderingDone(); //TODO clever rank of blockers - return 1; - } - return 0; -} - - - -int AIPlayer::combatDamages(){ - int result = 0; - GameObserver * gameObs = GameObserver::GetInstance(); - int currentGamePhase = gameObs->getCurrentGamePhase(); - - if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS) return orderBlockers(); - - if (currentGamePhase != Constants::MTG_PHASE_COMBATDAMAGE) return 0; - DamageResolverLayer * drl = gameObs->mLayers->combatLayer(); - - if (drl->currentChoosingPlayer == this){ - for (int i = 0; i < drl->mCount; i++){ - DamagerDamaged * current = (DamagerDamaged *) drl->mObjects[i]; - if (current->damageSelecter == this){ - OutputDebugString("YEs, AI IS THE DAMAGE DEALER"); - MTGCardInstance * attacker = current->card; - MTGCardInstance * canardEmissaire = *(attacker->blockers.rbegin()); - - while (canardEmissaire && current->damageToDeal){ - drl->clickDamage(canardEmissaire); - } - result = 1; - - } - } - } - - - if (result) return drl->nextPlayer(); - return 0; - -} - - -AIStats * AIPlayer::getStats(){ - if (!stats){ - char statFile[512]; - sprintf(statFile, RESPATH"/ai/baka/stats/%s.stats", opponent()->deckFileSmall.c_str()); - stats = NEW AIStats(this, statFile); - } - return stats; -} - -AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid){ - char deckFile[512]; - char avatarFile[512]; - char deckFileSmall[512]; - - if (deckid == -1){ //Evil twin - sprintf(deckFile, opponent->deckFile.c_str()); - OutputDebugString(opponent->deckFile.c_str()); - sprintf(avatarFile, "player/avatar.jpg"); - sprintf(deckFileSmall, "ai_baka_eviltwin"); - }else{ - if (!deckid){ - int nbdecks = 0; - int found = 1; - while (found){ - found = 0; - char buffer[512]; - sprintf(buffer, RESPATH"/ai/baka/deck%i.txt",nbdecks+1); - std::ifstream file(buffer); - if(file){ - found = 1; - file.close(); - nbdecks++; - } - } - if (!nbdecks) return NULL; - deckid = 1 + rand() % (nbdecks); - } - sprintf(deckFile, RESPATH"/ai/baka/deck%i.txt",deckid); - sprintf(avatarFile, "ai/baka/avatars/avatar%i.jpg",deckid); - sprintf(deckFileSmall, "ai_baka_deck%i",deckid); - } - - - MTGDeck * tempDeck = NEW MTGDeck(deckFile, NULL, collection); - MTGPlayerCards * deck = NEW MTGPlayerCards(collection,tempDeck); - delete tempDeck; - AIPlayerBaka * baka = NEW AIPlayerBaka(deck,deckFile, deckFileSmall, avatarFile); - return baka; -} - - -MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * potentialMana, const char * type){ - int maxCost = -1; - MTGCardInstance * nextCardToPlay = NULL; - MTGCardInstance * card = NULL; - CardDescriptor cd; - cd.init(); - cd.setType(type); - card = NULL; - while((card = cd.nextmatch(game->hand, card))){ - int currentCost = card->getManaCost()->getConvertedCost(); - if (currentCost > maxCost && potentialMana->canAfford(card->getManaCost())){ - TargetChooserFactory * tcf = NEW TargetChooserFactory(); - TargetChooser * tc = tcf->createTargetChooser(card); - delete tcf; - if (tc){ - int hasTarget = (chooseTarget(tc)); - delete tc; - if (!hasTarget)continue; - }else{ - int shouldPlayPercentage = 10; - int shouldPlay = effectBadOrGood(card); - if (shouldPlay == BAKA_EFFECT_GOOD){ - shouldPlayPercentage = 90; - }else if(BAKA_EFFECT_DONTKNOW == shouldPlay){ - shouldPlayPercentage = 80; - } - if (rand() % 100 > shouldPlayPercentage) continue; - } - nextCardToPlay = card; - maxCost = currentCost; - } - } - return nextCardToPlay; -} - -AIPlayerBaka::AIPlayerBaka(MTGPlayerCards * _deck, char * file, const char * fileSmall, char * avatarFile): AIPlayer(_deck,file, fileSmall){ - if (fileExists(avatarFile)){ - mAvatarTex = JRenderer::GetInstance()->LoadTexture(avatarFile, TEX_TYPE_USE_VRAM); - }else{ - mAvatarTex = JRenderer::GetInstance()->LoadTexture("ai/baka/avatar.jpg", TEX_TYPE_USE_VRAM); - } - if (mAvatarTex) - mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); - initTimer(); -} - -void AIPlayerBaka::initTimer(){ - timer = 0.1; -} - -int AIPlayerBaka::computeActions(){ - GameObserver * g = GameObserver::GetInstance(); - Player * p = g->currentPlayer; - if (!(g->currentlyActing() == this)) return 0; - if (g->mLayers->actionLayer()->menuObject){ - g->mLayers->actionLayer()->doReactTo(0); - return 1; - } - if (chooseTarget()) return 1; - int currentGamePhase = g->getCurrentGamePhase(); - if (g->isInterrupting == this){ // interrupting - selectAbility(); - return 1; - }else if (p == this && g->mLayers->stackLayer()->count(0,NOT_RESOLVED) == 0){ //standard actions - CardDescriptor cd; - MTGCardInstance * card = NULL; - switch(currentGamePhase){ - case Constants::MTG_PHASE_FIRSTMAIN: - case Constants::MTG_PHASE_SECONDMAIN: - if (canPutLandsIntoPlay){ - //Attempt to put land into play - cd.init(); - cd.setColor(Constants::MTG_COLOR_LAND); - card = cd.match(game->hand); - if (card){ - AIAction * a = NEW AIAction(card); - clickstream.push(a); - return 1; - } - } - - //No mana, try to get some - getPotentialMana(); - if (potentialMana->getConvertedCost() > 0){ - - - //look for the most expensive creature we can afford - nextCardToPlay = FindCardToPlay(potentialMana, "creature"); - //Let's Try an enchantment maybe ? - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery"); - if (nextCardToPlay){ -#if defined (WIN32) || defined (LINUX) - char buffe[4096]; - sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName()); - OutputDebugString(buffe); -#endif - - tapLandsForMana(potentialMana,nextCardToPlay->getManaCost()); - AIAction * a = NEW AIAction(nextCardToPlay); - clickstream.push(a); - return 1; - }else{ - selectAbility(); - } - }else{ - selectAbility(); - } - break; - case Constants::MTG_PHASE_COMBATATTACKERS: - chooseAttackers(); - break; - default: - selectAbility(); - break; - } - }else{ - switch(currentGamePhase){ - case Constants::MTG_PHASE_COMBATBLOCKERS: - chooseBlockers(); - break; - default: - break; - } - return 1; - } - return 1; -}; - -int AIPlayerBaka::Act(float dt){ - GameObserver * g = GameObserver::GetInstance(); - - if (!(g->currentlyActing() == this)){ - OutputDebugString("Cannot interrupt\n"); - return 0; - } - - int currentGamePhase = g->getCurrentGamePhase(); - - if (currentGamePhase == Constants::MTG_PHASE_CLEANUP && currentGamePhase != oldGamePhase){ - if (getStats()) getStats()->updateStats(); - } - oldGamePhase = currentGamePhase; - - timer-= dt; - if (AManaProducer::currentlyTapping || timer>0){ - return 0; - } - initTimer(); - if (combatDamages()){ - OutputDebugString("Damages and NOTHING ELSE\n"); - return 0; - } - interruptIfICan(); - if (!(g->currentlyActing() == this)){ - OutputDebugString("Cannot interrupt\n"); - return 0; - } - if (clickstream.empty()) computeActions(); - if (clickstream.empty()){ - if (g->isInterrupting == this){ - g->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption(); - }else{ - g->userRequestNextGamePhase(); - } - } else { - AIAction * action = clickstream.front(); - action->Act(); - SAFE_DELETE(action); - clickstream.pop(); - } - - - return 1; -}; - + if (amp && canHandleCost(amp)){ + MTGCardInstance * card = amp->source; + if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost()==1){ + potentialMana->add(amp->output); + used[card] = true; + } + } + } + + return potentialMana; +} + + +int AIPlayer::getEfficiency(AIAction * action){ + return action->getEfficiency(); +} + +int AIPlayer::canHandleCost(MTGAbility * ability){ + //Can't handle sacrifice costs that require a target yet :( + if (ability->cost){ + ExtraCosts * ec = ability->cost->extraCosts; + if (ec){ + for (size_t i = 0; i < ec->costs.size(); i++){ + if (ec->costs[i]->tc) return 0; + } + } + } + return 1; +} + +int AIAction::getEfficiency(){ + //TODO add multiplier according to what the player wants + if (efficiency != -1) return efficiency; + if (!ability) return 0; + GameObserver * g = GameObserver::GetInstance(); + ActionStack * s = g->mLayers->stackLayer(); + Player * p = g->currentlyActing(); + if (s->has(ability)) return 0; + + MTGAbility * a = ability; + GenericTargetAbility * gta = dynamic_cast(a); + if (gta) a = gta->ability; + + GenericActivatedAbility * gaa = dynamic_cast(a); + if (gaa) a = gaa->ability; + + if (!a){ + OutputDebugString("FATAL: Ability is NULL in AIAction::getEfficiency()"); + return 0; + } + + if (!((AIPlayer *)p)->canHandleCost(ability)) return 0; + + switch (a->aType){ + case MTGAbility::DAMAGER: + { + AADamager * aad = (AADamager *) a; + if ( p == target->controller()){ + efficiency = 0; + }else if (aad->damage >= target->toughness){ + efficiency = 100; + }else if (target->toughness){ + efficiency = (50 * aad->damage) / target->toughness; + }else{ + efficiency = 0; + } + break; + } + case MTGAbility::STANDARD_REGENERATE: + { + MTGCardInstance * _target = (MTGCardInstance *)(a->target); + efficiency = 0; + if (!_target->regenerateTokens && g->getCurrentGamePhase()< Constants::MTG_PHASE_COMBATDAMAGE && (_target->defenser || _target->blockers.size())){ + efficiency = 95; + } + //TODO If the card is the target of a damage spell + break; + } + case MTGAbility::MANA_PRODUCER: //can't use mana producers right now :/ + efficiency = 0; + break; + default: + if (target){ + efficiency = rand() % 5; //Small percentage of chance for other abilities + }else{ + efficiency = rand() % 10; + } + break; + } + return efficiency; +} + + + + +int AIPlayer::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, map * ranking){ + if (!a->tc){ + AIAction * as = NEW AIAction(a,c,NULL); + (*ranking)[as] = 1; + return 1; + } + GameObserver * g = GameObserver::GetInstance(); + for (int i = 0; i < 2; i++){ + Player * p = g->players[i]; + MTGGameZone * playerZones[] = {p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay}; + for (int j = 0; j < 4; j++){ + MTGGameZone * zone = playerZones[j]; + for (int k=0; k < zone->nb_cards; k++){ + MTGCardInstance * t = zone->cards[k]; + if (a->tc->canTarget(t)){ + + AIAction * as = NEW AIAction(a,c,t); + (*ranking)[as] = 1; + } + } + } + } + return 1; +} + +int AIPlayer::selectAbility(){ + mapranking; + list::iterator it; + ManaCost * pMana = getPotentialMana(); + GameObserver * g = GameObserver::GetInstance(); + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish + //Make sure we can use the ability + MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]); + for (int j=0; j < game->inPlay->nb_cards; j++){ + MTGCardInstance * card = game->inPlay->cards[j]; + if (a->isReactingToClick(card,pMana)){ + createAbilityTargets(a, card, &ranking); + } + } + } + + if (ranking.size()){ + OutputDebugString("We have a winrar\n"); + AIAction * a = ranking.begin()->first; + int chance = 1 + rand() % 100; + if (getEfficiency(a) < chance){ + a = NULL; + }else{ +OutputDebugString("We REALLY have a winner\n"); + tapLandsForMana(pMana, a->ability->cost); + clickstream.push(a); + } + map::iterator it2; + for (it2 = ranking.begin(); it2!=ranking.end(); it2++){ + if (a != it2->first) delete(it2->first); + } + } + return 1; +} + + + +int AIPlayer::interruptIfICan(){ + GameObserver * g = GameObserver::GetInstance(); + + if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this){ + if (!clickstream.empty()) g->mLayers->stackLayer()->cancelInterruptOffer(); + else g->mLayers->stackLayer()->setIsInterrupting(this); + return 1; + } + return 0; +} + +int AIPlayer::effectBadOrGood(MTGCardInstance * card){ + int id = card->getMTGId(); + AbilityFactory * af = NEW AbilityFactory(); + int autoGuess = af->magicText(id,NULL,card); + delete af; + if (autoGuess) return autoGuess; + return BAKA_EFFECT_DONTKNOW; +} + + + +int AIPlayer::chooseTarget(TargetChooser * tc){ + Targetable * potentialTargets[50]; + int nbtargets = 0; + GameObserver * gameObs = GameObserver::GetInstance(); + int checkOnly = 0; + if (tc){ + checkOnly = 1; + }else{ + tc = gameObs->getCurrentTargetChooser(); + } + if (!tc) return 0; + if (!(gameObs->currentlyActing() == this)) return 0; + Player * target = this; + int cardEffect = effectBadOrGood(tc->source); + if (cardEffect != BAKA_EFFECT_GOOD){ + target = this->opponent(); + } + + + if (!tc->alreadyHasTarget(target) && tc->canTarget(target) && nbtargets < 50){ + for (int i = 0; i < 3; i++){ //Increase probability to target a player when this is possible + potentialTargets[nbtargets] = target; + nbtargets++; + } + if (checkOnly) return 1; + } + MTGPlayerCards * playerZones = target->game; + MTGGameZone * zones[] = {playerZones->hand,playerZones->library,playerZones->inPlay, playerZones->graveyard}; + for (int j = 0; j < 4; j++){ + MTGGameZone * zone = zones[j]; + for (int k=0; k< zone->nb_cards; k++){ + MTGCardInstance * card = zone->cards[k]; + if (!tc->alreadyHasTarget(card) && tc->canTarget(card) && nbtargets < 50){ + if (checkOnly) return 1; + int multiplier = 1; + if (getStats() && getStats()->isInTop(card,10)){ + multiplier++; + if (getStats()->isInTop(card,5)){ + multiplier++; + if (getStats()->isInTop(card,3)){ + multiplier++; + } + } + } + for (int l=0; l < multiplier; l++){ + potentialTargets[nbtargets] = card; + nbtargets++; + } + } + } + } + if (nbtargets){ + int i = rand() % nbtargets; + int type = potentialTargets[i]->typeAsTarget(); + switch(type){ + case TARGET_CARD: + { + MTGCardInstance * card = ((MTGCardInstance *) potentialTargets[i]); + clickstream.push(NEW AIAction(card)); + return 1; + break; + } + case TARGET_PLAYER: + { + Player * player = ((Player *) potentialTargets[i]); + clickstream.push(NEW AIAction(player)); + return 1; + break; + } + } + } + //BIG PROBLEM + gameObs->cancelCurrentAction(); + return 0; +} + +int AIPlayer::getCreaturesInfo(Player * player, int neededInfo , int untapMode, int canAttack){ + int result = 0; + CardDescriptor cd; + cd.init(); + cd.setType("Creature"); + cd.unsecureSetTapped(untapMode); + MTGCardInstance * card = NULL; + while((card = cd.nextmatch(player->game->inPlay, card))){ + if (!canAttack || card->canAttack()){ + if (neededInfo == INFO_NBCREATURES){ + result++; + }else{ + result+=card->power; + } + } + } + return result; +} + + + +int AIPlayer::chooseAttackers(){ + //Attack with all creatures + //How much damage can the other player do during his next Attack ? + int opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER); + int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES); + int myForce = getCreaturesInfo(this,INFO_CREATURESPOWER,-1,1); + int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1,1); + bool attack = ((myCreatures > opponentCreatures) || (myForce > opponentForce) || (myForce > 2*opponent()->life)); + if (agressivity > 80 && !attack && life > opponentForce) { + opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES,-1); + opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER,-1); + attack = (myCreatures >= opponentCreatures && myForce > opponentForce) || (myForce > opponentForce) || (myForce > opponent()->life); + } + printf("Choose attackers : %i %i %i %i -> %i\n", opponentForce, opponentCreatures, myForce, myCreatures, attack); + if (attack){ + CardDescriptor cd; + cd.init(); + cd.setType("creature"); + MTGCardInstance * card = NULL; + GameObserver * g = GameObserver::GetInstance(); + MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_ATTACK_RULE); + while((card = cd.nextmatch(game->inPlay, card))){ + g->mLayers->actionLayer()->reactToClick(a,card); + } + } + return 1; +} + +/* Can I first strike my oponent and get away with murder ? */ +int AIPlayer::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy){ + if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) return 0; + if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) return 0; + if (!(card->power >= ennemy->toughness)) return 0; + return 1; +} + +int AIPlayer::chooseBlockers(){ + map opponentsToughness; + int opponentForce = getCreaturesInfo(opponent(),INFO_CREATURESPOWER); + //int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); + //int myForce = getCreaturesInfo(this,INFO_CREATURESPOWER); + //int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1); + CardDescriptor cd; + cd.init(); + cd.setType("Creature"); + cd.unsecureSetTapped(-1); + MTGCardInstance * card = NULL; + GameObserver * g = GameObserver::GetInstance(); + MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_BLOCK_RULE); + + while((card = cd.nextmatch(game->inPlay, card))){ + g->mLayers->actionLayer()->reactToClick(a,card); + int set = 0; + while(!set){ + if (!card->defenser){ + set = 1; + }else{ + MTGCardInstance * attacker = card->defenser; + map::iterator it = opponentsToughness.find(attacker); + if ( it == opponentsToughness.end()){ + opponentsToughness[attacker] = attacker->toughness; + it = opponentsToughness.find(attacker); + } + if (opponentsToughness[attacker] > 0 && getStats() && getStats()->isInTop(attacker,3,false)){ + opponentsToughness[attacker]-= card->power; + set = 1; + }else{ + g->mLayers->actionLayer()->reactToClick(a,card); + } + } + } + } + card = NULL; + while((card = cd.nextmatch(game->inPlay, card))){ + if (card->defenser && opponentsToughness[card->defenser] > 0){ + while (card->defenser){ + + g->mLayers->actionLayer()->reactToClick(a,card); + } + } + } + card = NULL; + while((card = cd.nextmatch(game->inPlay, card))){ + if(!card->defenser){ + g->mLayers->actionLayer()->reactToClick(a,card); + int set = 0; + while(!set){ + if (!card->defenser){ + set = 1; + }else{ + MTGCardInstance * attacker = card->defenser; + if (opponentsToughness[attacker] <= 0 || + (card->toughness <= attacker->power && opponentForce*2 nbOpponents()>1){ + g->mLayers->actionLayer()->reactToClick(a,card); + }else{ + set = 1; + } + } + } + } + } + return 1; +} + +int AIPlayer::orderBlockers(){ + GameObserver * g = GameObserver::GetInstance(); + /* + DamageResolverLayer * drl = g->mLayers->combatLayer(); + if (drl->orderingIsNeeded && g->currentPlayer==this){ + drl->blockersOrderingDone(); //TODO clever rank of blockers + return 1; + } + */ + return 0; +} + + + +int AIPlayer::combatDamages(){ + int result = 0; + GameObserver * gameObs = GameObserver::GetInstance(); + int currentGamePhase = gameObs->getCurrentGamePhase(); + + if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS) return orderBlockers(); + + if (currentGamePhase != Constants::MTG_PHASE_COMBATDAMAGE) return 0; + /* + DamageResolverLayer * drl = gameObs->mLayers->combatLayer(); + + if (drl->currentChoosingPlayer == this){ + for (int i = 0; i < drl->mCount; i++){ + DamagerDamaged * current = (DamagerDamaged *) drl->mObjects[i]; + if (current->damageSelecter == this){ + OutputDebugString("YEs, AI IS THE DAMAGE DEALER"); + MTGCardInstance * attacker = current->card; + MTGCardInstance * canardEmissaire = *(attacker->blockers.rbegin()); + + while (canardEmissaire && current->damageToDeal){ + drl->clickDamage(canardEmissaire); + } + result = 1; + + } + } + } + + + if (result) return drl->nextPlayer(); + */ + return 0; + +} + + +AIStats * AIPlayer::getStats(){ + if (!stats){ + char statFile[512]; + sprintf(statFile, RESPATH"/ai/baka/stats/%s.stats", opponent()->deckFileSmall.c_str()); + stats = NEW AIStats(this, statFile); + } + return stats; +} + +AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid){ + char deckFile[512]; + char avatarFile[512]; + char deckFileSmall[512]; + + if (deckid == -1){ //Evil twin + sprintf(deckFile, opponent->deckFile.c_str()); + OutputDebugString(opponent->deckFile.c_str()); + sprintf(avatarFile, "player/avatar.jpg"); + sprintf(deckFileSmall, "ai_baka_eviltwin"); + }else{ + if (!deckid){ + int nbdecks = 0; + int found = 1; + while (found){ + found = 0; + char buffer[512]; + sprintf(buffer, RESPATH"/ai/baka/deck%i.txt",nbdecks+1); + std::ifstream file(buffer); + if(file){ + found = 1; + file.close(); + nbdecks++; + } + } + if (!nbdecks) return NULL; + deckid = 1 + rand() % (nbdecks); + } + sprintf(deckFile, RESPATH"/ai/baka/deck%i.txt",deckid); + sprintf(avatarFile, "ai/baka/avatars/avatar%i.jpg",deckid); + sprintf(deckFileSmall, "ai_baka_deck%i",deckid); + } + + + MTGDeck * tempDeck = NEW MTGDeck(deckFile, NULL, collection); + MTGPlayerCards * deck = NEW MTGPlayerCards(collection,tempDeck); + delete tempDeck; + AIPlayerBaka * baka = NEW AIPlayerBaka(deck,deckFile, deckFileSmall, avatarFile); + return baka; +} + + +MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * potentialMana, const char * type){ + int maxCost = -1; + MTGCardInstance * nextCardToPlay = NULL; + MTGCardInstance * card = NULL; + CardDescriptor cd; + cd.init(); + cd.setType(type); + card = NULL; + while((card = cd.nextmatch(game->hand, card))){ + int currentCost = card->getManaCost()->getConvertedCost(); + if (currentCost > maxCost && potentialMana->canAfford(card->getManaCost())){ + TargetChooserFactory * tcf = NEW TargetChooserFactory(); + TargetChooser * tc = tcf->createTargetChooser(card); + delete tcf; + if (tc){ + int hasTarget = (chooseTarget(tc)); + delete tc; + if (!hasTarget)continue; + }else{ + int shouldPlayPercentage = 10; + int shouldPlay = effectBadOrGood(card); + if (shouldPlay == BAKA_EFFECT_GOOD){ + shouldPlayPercentage = 90; + }else if(BAKA_EFFECT_DONTKNOW == shouldPlay){ + shouldPlayPercentage = 80; + } + if (rand() % 100 > shouldPlayPercentage) continue; + } + nextCardToPlay = card; + maxCost = currentCost; + } + } + return nextCardToPlay; +} + +AIPlayerBaka::AIPlayerBaka(MTGPlayerCards * deck, string file, string fileSmall, string avatarFile) : AIPlayer(deck, file, fileSmall) { + if (fileExists(avatarFile.c_str())) + mAvatarTex = JRenderer::GetInstance()->LoadTexture(avatarFile.c_str(), TEX_TYPE_USE_VRAM); + else + mAvatarTex = JRenderer::GetInstance()->LoadTexture("ai/baka/avatar.jpg", TEX_TYPE_USE_VRAM); + if (mAvatarTex) + mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); + initTimer(); +} + +void AIPlayerBaka::initTimer(){ + timer = 0.1; +} + +int AIPlayerBaka::computeActions(){ + GameObserver * g = GameObserver::GetInstance(); + Player * p = g->currentPlayer; + if (!(g->currentlyActing() == this)) return 0; + if (g->mLayers->actionLayer()->menuObject){ + g->mLayers->actionLayer()->doReactTo(0); + return 1; + } + if (chooseTarget()) return 1; + int currentGamePhase = g->getCurrentGamePhase(); + if (g->isInterrupting == this){ // interrupting + selectAbility(); + return 1; + }else if (p == this && g->mLayers->stackLayer()->count(0,NOT_RESOLVED) == 0){ //standard actions + CardDescriptor cd; + MTGCardInstance * card = NULL; + switch(currentGamePhase){ + case Constants::MTG_PHASE_FIRSTMAIN: + case Constants::MTG_PHASE_SECONDMAIN: + if (canPutLandsIntoPlay){ + //Attempt to put land into play + cd.init(); + cd.setColor(Constants::MTG_COLOR_LAND); + card = cd.match(game->hand); + if (card){ + AIAction * a = NEW AIAction(card); + clickstream.push(a); + return 1; + } + } + + //No mana, try to get some + getPotentialMana(); + if (potentialMana->getConvertedCost() > 0){ + + + //look for the most expensive creature we can afford + nextCardToPlay = FindCardToPlay(potentialMana, "creature"); + //Let's Try an enchantment maybe ? + if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment"); + if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact"); + if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant"); + if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery"); + if (nextCardToPlay){ +#if defined (WIN32) || defined (LINUX) + char buffe[4096]; + sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName().c_str()); + OutputDebugString(buffe); +#endif + + tapLandsForMana(potentialMana,nextCardToPlay->getManaCost()); + AIAction * a = NEW AIAction(nextCardToPlay); + clickstream.push(a); + return 1; + }else{ + selectAbility(); + } + }else{ + selectAbility(); + } + break; + case Constants::MTG_PHASE_COMBATATTACKERS: + chooseAttackers(); + break; + default: + selectAbility(); + break; + } + }else{ + switch(currentGamePhase){ + case Constants::MTG_PHASE_COMBATBLOCKERS: + chooseBlockers(); + break; + default: + break; + } + return 1; + } + return 1; +}; + +int AIPlayerBaka::Act(float dt){ + GameObserver * g = GameObserver::GetInstance(); + + if (!(g->currentlyActing() == this)){ + OutputDebugString("Cannot interrupt\n"); + return 0; + } + + int currentGamePhase = g->getCurrentGamePhase(); + + if (currentGamePhase == Constants::MTG_PHASE_CLEANUP && currentGamePhase != oldGamePhase){ + if (getStats()) getStats()->updateStats(); + } + oldGamePhase = currentGamePhase; + + timer-= dt; + if (AManaProducer::currentlyTapping || timer>0){ + return 0; + } + initTimer(); + if (combatDamages()){ + OutputDebugString("Damages and NOTHING ELSE\n"); + return 0; + } + interruptIfICan(); + if (!(g->currentlyActing() == this)){ + OutputDebugString("Cannot interrupt\n"); + return 0; + } + if (clickstream.empty()) computeActions(); + if (clickstream.empty()){ + if (g->isInterrupting == this){ + g->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption(); + }else{ + g->userRequestNextGamePhase(); + } + } else { + AIAction * action = clickstream.front(); + action->Act(); + SAFE_DELETE(action); + clickstream.pop(); + } + return 1; +}; + diff --git a/projects/mtg/src/ActionLayer.cpp b/projects/mtg/src/ActionLayer.cpp index d0a0ea3d5..cca909ad0 100644 --- a/projects/mtg/src/ActionLayer.cpp +++ b/projects/mtg/src/ActionLayer.cpp @@ -67,16 +67,15 @@ void ActionLayer::Update(float dt){ return; } modal = 0; - GameObserver * g = GameObserver::GetInstance(); + GameObserver* game = GameObserver::GetInstance(); for (int i=mCount -1 ;i>=0;i--){ if (mObjects[i]!= NULL){ ActionElement * currentAction = (ActionElement *)mObjects[i]; - if (currentAction->testDestroy()){ - g->removeObserver(currentAction); - } + if (currentAction->testDestroy()) + game->removeObserver(currentAction); } } - int newPhase = g->getCurrentGamePhase(); + int newPhase = game->getCurrentGamePhase(); for (int i=0;ireactToTargetClick(menuObject); diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index aac82cb71..91768f6f9 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -8,8 +8,8 @@ #include "../include/Damage.h" #include "../include/ManaCost.h" #include "../include/GameOptions.h" +#include "../include/TexturesCache.h" #include "../include/TargetChooser.h" -// WALDORF - added to support drawing big cards during interrupts #include "../include/CardGui.h" #include "../include/Translate.h" @@ -57,7 +57,7 @@ void StackAbility::Render(){ sprintf(buffer, "%s", _(ability->getMenuText()).c_str()); mFont->DrawString(buffer, x + 30 , y, JGETEXT_LEFT); JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = ability->source->getThumb(); + JQuad * quad = cache.getThumb(ability->source); if (quad){ quad->SetColor(ARGB(255,255,255,255)); float scale = 30 / quad->mHeight; @@ -115,7 +115,7 @@ Spell::Spell(int id, MTGCardInstance * _source, TargetChooser * tc, ManaCost * _ } -const char * Spell::getDisplayName(){ +const string Spell::getDisplayName(){ return source->getName(); } @@ -133,10 +133,10 @@ int Spell::resolve(){ if (!source->hasType("instant") && !source->hasType("sorcery")){ source = source->controller()->game->putInPlay(source); } - + //Play SFX - if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME].getIntValue() > 0){ + if (options[Options::SFXVOLUME].number > 0){ JSample * sample = source->getSample(); if (sample){ JSoundSystem::GetInstance()->PlaySample(sample); @@ -188,7 +188,7 @@ void Spell::Render(){ mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); mFont->DrawString(_(source->name).c_str(), x + 30 , y, JGETEXT_LEFT); JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = source->getThumb(); + JQuad * quad = cache.getThumb(source); if (quad){ quad->SetColor(ARGB(255,255,255,255)); float scale = mHeight / quad->mHeight; @@ -205,7 +205,7 @@ void Spell::Render(){ // just overwrites it. // I stole the render code from RenderBig() in CardGUI.cpp - quad = source->getQuad(); + quad = cache.getQuad(source); if (quad){ quad->SetColor(ARGB(220,255,255,255)); float scale = 257.f / quad->mHeight; @@ -214,9 +214,9 @@ void Spell::Render(){ else { MTGCard * mtgcard = source->model; - CardGui::alternateRender(mtgcard, NULL, 10 + 90 , 20 + 130, 0.0f,0.9f); + // CardGui::alternateRender(mtgcard, NULL, 10 + 90 , 20 + 130, 0.0f,0.9f); - quad = source->getThumb(); + quad = cache.getThumb(source); if (quad){ float scale = 250 / quad->mHeight; quad->SetColor(ARGB(40,255,255,255)); @@ -276,7 +276,7 @@ void PutInGraveyard::Render(){ mFont->DrawString(_("is exiled").c_str(), x + 30 , y, JGETEXT_LEFT); } JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = card->getThumb(); + JQuad * quad = cache.getThumb(card); if (quad){ quad->SetColor(ARGB(255,255,255,255)); float scale = 30 / quad->mHeight; @@ -330,11 +330,10 @@ int ActionStack::addPutInGraveyard(MTGCardInstance * card){ int ActionStack::addAbility(MTGAbility * ability){ StackAbility * stackAbility = NEW StackAbility(mCount,ability); int result = addAction(stackAbility); - if (!game->players[0]->isAI() && - ability->source->controller()==game->players[0] && - GameOptions::GetInstance()->values[OPTIONS_INTERRUPTMYABILITIES].getIntValue() == 0){ - interruptDecision[0] = DONT_INTERRUPT; - } + if (!game->players[0]->isAI() && + ability->source->controller()==game->players[0] && + 0 == options[Options::INTERRUPTMYABILITIES].number) + interruptDecision[0] = DONT_INTERRUPT; return result; } @@ -388,11 +387,10 @@ Spell * ActionStack::addSpell(MTGCardInstance * _source, TargetChooser * tc, Man #endif Spell * spell = NEW Spell(mCount,_source,tc, mana); addAction(spell); - if (!game->players[0]->isAI() && - _source->controller()==game->players[0] && - GameOptions::GetInstance()->values[OPTIONS_INTERRUPTMYSPELLS].getIntValue() == 0){ - interruptDecision[0] = DONT_INTERRUPT; - } + if (!game->players[0]->isAI() && + _source->controller()==game->players[0] && + 0 == options[Options::INTERRUPTMYSPELLS].number) + interruptDecision[0] = DONT_INTERRUPT; return spell; } @@ -403,10 +401,9 @@ Interruptible * ActionStack::getAt(int id){ return (Interruptible *)mObjects[id]; } -ActionStack::ActionStack(int id, GameObserver* _game):GuiLayer(id, _game){ - for (int i=0; i<2; i++){ +ActionStack::ActionStack(GameObserver* game) : game(game){ + for (int i=0; i<2; i++) interruptDecision[i] = 0; - } askIfWishesToInterrupt = NULL; timer = -1; currentState = -1; @@ -644,9 +641,9 @@ void ActionStack::Update(float dt){ // WALDORF - added code to use a game option setting to determine how // long the Interrupt timer should be. If it is set to zero (0), the // game will wait for ever for the user to make a selection. - if (GameOptions::GetInstance()->values[OPTIONS_INTERRUPT_SECONDS].getIntValue() > 0) + if (options[Options::INTERRUPT_SECONDS].number > 0) { - if (timer < 0) timer = GameOptions::GetInstance()->values[OPTIONS_INTERRUPT_SECONDS].getIntValue(); + if (timer < 0) timer = options[Options::INTERRUPT_SECONDS].number; timer -= dt; if (timer < 0) cancelInterruptOffer(); } @@ -736,7 +733,7 @@ bool ActionStack::CheckUserInput(u32 key){ return true; //Steal the input to other layers if we're visible } if (PSP_CTRL_TRIANGLE == key){ - if (modal) {modal = 0;} else {modal = 1;} + if (modal) modal = 0; else modal = 1; return true; } } @@ -753,13 +750,12 @@ int ActionStack::CombatDamages(){ } int ActionStack::CombatDamages(int strike){ - DamageStack * damages = NEW DamageStack(mCount,game); + DamageStack * damages = NEW DamageStack(game); int damageitems = damages->CombatDamages(strike); - if (damageitems){ + if (damageitems) addAction(damages); - }else{ + else SAFE_DELETE(damages); - } return damageitems; } @@ -773,9 +769,8 @@ while( iter != mObjects.end() ){ iter = mObjects.erase( iter ) ; mCount--; SAFE_DELETE(current); - }else { - ++iter ; - } + } else + ++iter; } return 1; } @@ -842,7 +837,7 @@ void ActionStack::Render(){ // WALDORF - changed "interrupt ?" to "Interrupt?". Don't display count down // seconds if the user disables auto progressing interrupts by setting the seconds // value to zero in Options. - if (GameOptions::GetInstance()->values[OPTIONS_INTERRUPT_SECONDS].getIntValue() == 0) + if (options[Options::INTERRUPT_SECONDS].number == 0) sprintf(buffer, _("Interrupt?").c_str()); else sprintf(buffer, "%s %i", _("Interrupt?").c_str(),static_cast(timer)); @@ -935,7 +930,7 @@ void Interruptible::Dump(){ sstate = "unknown"; break; } - + char buf[4096]; sprintf(buf, " type %s(%i) - state %s(%i) - display %i\n", stype.c_str(), type, sstate.c_str(),state, display); OutputDebugString(buf); diff --git a/projects/mtg/src/Blocker.cpp b/projects/mtg/src/Blocker.cpp index 286b7f39c..8cf70c455 100644 --- a/projects/mtg/src/Blocker.cpp +++ b/projects/mtg/src/Blocker.cpp @@ -24,11 +24,11 @@ void UntapBlocker::init(ManaCost * _cost){ manaCost = _cost; } - UntapBlocker * UntapBlocker::clone() const{ - UntapBlocker * a = NEW UntapBlocker(*this); - a->isClone = 1; - return a; - } +UntapBlocker * UntapBlocker::clone() const{ + UntapBlocker * a = NEW UntapBlocker(*this); + a->isClone = 1; + return a; +} //Default behaviour for blockers : they block the card they're attached to @@ -45,7 +45,7 @@ void UntapBlocker::Update(float dt){ _target->getUntapBlockers()->Add(this); #if defined (WIN32) || defined (LINUX) char buf[4096]; - sprintf(buf, "Adding Blocker to %s \n", _target->model->getName()); + sprintf(buf, "Adding Blocker to %s \n", _target->model->getName().c_str()); OutputDebugString(buf); #endif } diff --git a/projects/mtg/src/CardDisplay.cpp b/projects/mtg/src/CardDisplay.cpp index 118f71895..e135b6c7c 100644 --- a/projects/mtg/src/CardDisplay.cpp +++ b/projects/mtg/src/CardDisplay.cpp @@ -4,8 +4,8 @@ #include "../include/TargetChooser.h" #include "../include/MTGGameZones.h" -CardDisplay::CardDisplay():PlayGuiObjectController(0, GameObserver::GetInstance()){ - tc= NULL; +CardDisplay::CardDisplay() : mId(0), game(GameObserver::GetInstance()) { + tc = NULL; listener = NULL; nb_displayed_items = 7; start_item = 0; @@ -13,8 +13,8 @@ CardDisplay::CardDisplay():PlayGuiObjectController(0, GameObserver::GetInstance( y= 0; } -CardDisplay::CardDisplay(int id, GameObserver* _game, int _x, int _y, JGuiListener * _listener, TargetChooser * _tc, int _nb_displayed_items ):PlayGuiObjectController(id, _game), x(_x), y(_y){ - tc= _tc; +CardDisplay::CardDisplay(int id, GameObserver* game, int _x, int _y, JGuiListener * _listener, TargetChooser * _tc, int _nb_displayed_items ) : mId(id), game(game), x(_x), y(_y) { + tc = _tc; listener = _listener; nb_displayed_items = _nb_displayed_items; start_item = 0; @@ -22,7 +22,7 @@ CardDisplay::CardDisplay(int id, GameObserver* _game, int _x, int _y, JGuiListen void CardDisplay::AddCard(MTGCardInstance * _card){ - CardGui * card = NEW CardGui(mCount, _card, 40, x + 5 + (mCount - start_item) * 30, y + 5, (mCount == 0)); + CardGui * card = NEW CardView(_card, x + 5 + (mCount - start_item) * 30, y + 5); Add(card); } @@ -60,7 +60,7 @@ bool CardDisplay::CheckUserInput(u32 key){ if (listener){ listener->ButtonPressed(mId, 0); return true; - } + } } if (!mCount) @@ -75,7 +75,7 @@ bool CardDisplay::CheckUserInput(u32 key){ tc->toggleTarget(cardg->card); return true; }else{ - if (game) game->ButtonPressed(mId, cardg); + if (game) game->ButtonPressed(cardg); return true; } } @@ -140,7 +140,7 @@ void CardDisplay::Render(){ if (mCount && mObjects[mCurr] != NULL){ mObjects[mCurr]->Render(); CardGui * cardg = ((CardGui *)mObjects[mCurr]); - cardg->RenderBig(-1,-1,showBigCards-1); + // cardg->RenderBig(-1,-1,showBigCards-1); } } @@ -149,7 +149,7 @@ ostream& CardDisplay::toString(ostream& out) const return (out << "CardDisplay ::: x,y : " << x << "," << y << " ; start_item : " << start_item << " ; nb_displayed_items " << nb_displayed_items << " ; tc : " << tc << " ; listener : " << listener); } -DefaultTargetDisplay::DefaultTargetDisplay(int id, GameObserver* _game, int _x, int _y,JGuiListener * _listener, int _nb_displayed_items ):CardDisplay(id, _game, _x, _y, _listener, NULL, _nb_displayed_items ){ +DefaultTargetDisplay::DefaultTargetDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener, int nb_displayed_items ):CardDisplay(id, game, x, y, listener, NULL, nb_displayed_items ){ tc = NEW TargetChooser(); } diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index cad80945f..eed602748 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -1,3 +1,4 @@ +#include "JGE.h" #include "../include/config.h" #include "../include/CardGui.h" #include "../include/ManaCostHybrid.h" @@ -6,6 +7,231 @@ #include "../include/MTGDefinitions.h" #include +CardGui::CardGui(MTGCardInstance* card, float x, float y) : PlayGuiObject(Height, x, y, false), quad(cache.getQuad(card)), card(card) {} +CardGui::CardGui(MTGCardInstance* card, const Pos& ref) : PlayGuiObject(Height, ref, false), quad(cache.getQuad(card)), card(card) {} + +CardView::CardView(MTGCardInstance* card, float x, float y) : CardGui(card, x, y) { + card->view = this; +} + +CardView::CardView(MTGCardInstance* card, const Pos& ref) : CardGui(card, ref) { + card->view = this; +} + +void CardView::Update(float dt) +{ + PlayGuiObject::Update(dt); +} + +void CardView::Render() +{ + JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MAIN_FONT); + + JRenderer * renderer = JRenderer::GetInstance(); + GameObserver * game = GameObserver::GetInstance(); + + TargetChooser * tc = NULL; + if (game) tc = game->getCurrentTargetChooser(); + + if (quad) { + const float scale = actZ * 40 / quad->mHeight; + renderer->RenderQuad(GameApp::CommonRes->GetQuad("shadow"), actX + (scale-1)*15, actY + (scale-1)*15, actT, 28*scale, 40*scale); + quad->SetColor(ARGB(static_cast(actA),255,255,255)); + renderer->RenderQuad(quad, actX, actY, actT, scale, scale); + } + else { + int color = card->getColor(); + MTGCard * mtgcard = card->model; + const float scale = actZ; + + renderer->RenderQuad(GameApp::CommonRes->GetQuad("shadow"), actX + (scale-1)*15, actY + (scale-1)*15, actT, 28*scale, 40*scale); + + mFont->SetColor(ARGB(static_cast(actA), 0, 0, 0)); + + JQuad * icon = NULL; + if (card->hasSubtype("plains")) + icon = GameApp::CommonRes->GetQuad("c_white"); + else if (card->hasSubtype("swamp")) + icon = GameApp::CommonRes->GetQuad("c_black"); + else if (card->hasSubtype("forest")) + icon = GameApp::CommonRes->GetQuad("c_green"); + else if (card->hasSubtype("mountain")) + icon = GameApp::CommonRes->GetQuad("c_red"); + else if (card->hasSubtype("island")) + icon = GameApp::CommonRes->GetQuad("c_blue"); + if (icon) icon->SetHotSpot(16,16); + + { + JQuad* q; + // Draw the "unknown" card model + switch(card->getColor()) + { + case Constants::MTG_COLOR_GREEN: q = GameApp::CommonRes->GetQuad("green_thumb"); break; + case Constants::MTG_COLOR_BLUE : q = GameApp::CommonRes->GetQuad("blue_thumb"); break; + case Constants::MTG_COLOR_RED : q = GameApp::CommonRes->GetQuad("red_thumb"); break; + case Constants::MTG_COLOR_BLACK: q = GameApp::CommonRes->GetQuad("black_thumb"); break; + case Constants::MTG_COLOR_WHITE: q = GameApp::CommonRes->GetQuad("white_thumb"); break; + default: q = GameApp::CommonRes->GetQuad("black_thumb"); break; + } + q->SetColor(ARGB(static_cast(actA),255,255,255)); + renderer->RenderQuad(q, actX, actY, actT, scale, scale); + } + + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE * 0.5 * actZ); + mFont->DrawString(card->getName().c_str(), actX - actZ * Width / 2 + 1, actY - actZ * Height / 2 + 1); + if (icon) { icon->SetColor(ARGB(static_cast(actA),255,255,255)); renderer->RenderQuad(icon, actX, actY, 0); } + if (tc && !tc->canTarget(card)) renderer->FillRect(actX - actZ*Width/2, actY - actZ*Height/2, actZ*Width, actZ*Height, ARGB(200,0,0,0)); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + } + + if (card->isCreature()){ + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + char buffer[200]; + sprintf(buffer, "%i/%i",card->power,card->life); + renderer->FillRect(actX + 2, actY + 30 - 12, 25, 12, ARGB(((static_cast(actA))/2),0,0,0)); + mFont->SetColor(ARGB(static_cast(actA),255,255,255)); + mFont->DrawString(buffer, actX + 4, actY + 30 - 10); + } + + PlayGuiObject::Render(); +} + +void CardGui::RenderBig(const Pos& pos){ + JRenderer * renderer = JRenderer::GetInstance(); + + if (quad){ + quad->SetColor(ARGB((int)pos.actA,255,255,255)); + float scale = pos.actZ * 257.f / quad->mHeight; + renderer->RenderQuad(quad, pos.actX, pos.actY, pos.actT, scale, scale); + return; + } + + JQuad * q; + if ((q = cache.getThumb(card))) + { + float scale = pos.actZ * 250 / q->mHeight; + q->SetColor(ARGB((int)pos.actA,255,255,255)); + renderer->RenderQuad(q, pos.actX, pos.actY, pos.actT, scale, scale); + return; + } + + // If we come here, we do not have the picture. + + // Draw the "unknown" card model + MTGCard * mtgcard = card->model; + switch(card->getColor()) + { + case Constants::MTG_COLOR_GREEN: q = GameApp::CommonRes->GetQuad("green"); break; + case Constants::MTG_COLOR_BLUE : q = GameApp::CommonRes->GetQuad("blue"); break; + case Constants::MTG_COLOR_RED : q = GameApp::CommonRes->GetQuad("red"); break; + case Constants::MTG_COLOR_BLACK: q = GameApp::CommonRes->GetQuad("black"); break; + case Constants::MTG_COLOR_WHITE: q = GameApp::CommonRes->GetQuad("white"); break; + default: q = GameApp::CommonRes->GetQuad("black"); break; + } + float scale = pos.actZ * 250 / q->mHeight; + q->SetColor(ARGB((int)pos.actA,255,255,255)); + renderer->RenderQuad(q, pos.actX, pos.actY, pos.actT, scale, scale); + + // Write the title + JLBFont * font = GameApp::CommonRes->GetJLBFont("graphics/magic"); + float backup_scale = font->GetScale(); + font->SetColor(ARGB((int)pos.actA, 0, 0, 0)); + font->SetScale(0.8 * pos.actZ); + + { + const char* name = _(card->getName()).c_str(); + float w = font->GetStringWidth(name) * 0.8 * pos.actZ; + if (w > BigWidth - 30) + font->SetScale((BigWidth - 30) / w); + font->DrawString(name, pos.actX + 22 - BigWidth / 2, pos.actY + 22 - BigHeight / 2); + } + + // Write the description + { + font->SetScale(0.8 * pos.actZ); + const std::vector txt = card->formattedText(); + unsigned i = 0; + for (std::vector::const_iterator it = txt.begin(); it != txt.end(); ++it, ++i) + font->DrawString(it->c_str(), pos.actX + 22 - BigWidth / 2, pos.actY + 35 + 11 * i); + } + + // Write the strength + if (card->isCreature()) + { + char buffer[32]; + sprintf(buffer, "%i/%i", card->power, card->life); + float w = font->GetStringWidth(buffer) * 0.8; + font->DrawString(buffer, pos.actX + 65 - w / 2, pos.actY + 106); + } + + // Mana + { + ManaCost* manacost = card->getManaCost(); + ManaCostHybrid* h; + unsigned int j = 0; + unsigned char t = (JGE::GetInstance()->GetTime() / 3) & 0xFF; + unsigned char v = t + 127; + while ((h = manacost->getHybridCost(j))) + { + float scale = pos.actZ * 0.05 * cosf(2*M_PI*((float)t)/256.0); + if (scale < 0) + { + renderer->RenderQuad(manaIcons[h->color1], pos.actX - 12 * j + 75 + 3 * sinf(2*M_PI*((float)t)/256.0), pos.actY - 115 + 3 * cosf(2*M_PI*((float)(t-35))/256.0), 0, 0.4 + scale, 0.4 + scale); + renderer->RenderQuad(manaIcons[h->color2], pos.actX - 12 * j + 75 + 3 * sinf(2*M_PI*((float)v)/256.0), pos.actY - 115 + 3 * cosf(2*M_PI*((float)(v-35))/256.0), 0, 0.4 - scale, 0.4 - scale); + } + else + { + renderer->RenderQuad(manaIcons[h->color2], pos.actX - 12 * j + 75 + 3 * sinf(2*M_PI*((float)v)/256.0), pos.actY - 115 + 3 * cosf(2*M_PI*((float)(v-35))/256.0), 0, 0.4 - scale, 0.4 - scale); + renderer->RenderQuad(manaIcons[h->color1], pos.actX - 12 * j + 75 + 3 * sinf(2*M_PI*((float)t)/256.0), pos.actY - 115 + 3 * cosf(2*M_PI*((float)(t-35))/256.0), 0, 0.4 + scale, 0.4 + scale); + } + ++j; + } + for (int i = Constants::MTG_NB_COLORS - 2; i >= 1; --i) + { + for (int cost = manacost->getCost(i); cost > 0; --cost) + { + renderer->RenderQuad(manaIcons[i], pos.actX - 12*j + 75, pos.actY - 115, 0, 0.4 * pos.actZ, 0.4 * pos.actZ); + ++j; + } + } + // Colorless mana + if (int cost = manacost->getCost(0)) + { + char buffer[10]; + sprintf(buffer, "%d", cost); + renderer->RenderQuad(manaIcons[0], pos.actX - 12*j + 75, pos.actY - 115, 0, 0.4 * pos.actZ, 0.4 * pos.actZ); + float w = font->GetStringWidth(buffer); + font->DrawString(buffer, pos.actX - 12*j + 76 - w/2, pos.actY - 120); + } + } + + { + string s = ""; + for (int i = card->nb_types - 1; i > 0; --i) + { + s += _(Subtypes::subtypesList->find(card->types[i])); + s += " - "; + } + s += _(Subtypes::subtypesList->find(card->types[0])); + font->DrawString(s.c_str(), pos.actX + 22 - BigWidth / 2, pos.actY + 17); + } + + font->SetScale(backup_scale); +} + + + +MTGCardInstance* CardView::getCard() { return card; } + +TransientCardView::TransientCardView(MTGCardInstance* card, float x, float y) : CardView(card, x, y){} +TransientCardView::TransientCardView(MTGCardInstance* card, const Pos& ref) : CardView(card, ref.actX, ref.actY) {}; +void TransientCardView::Render() +{ + CardView::Render(); +} + + +/* void CardGui::alternateRender(MTGCard * card, JQuad ** manaIcons, float x, float y, float rotation, float scale){ JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MAGIC_FONT); float backup = mFont->GetScale(); @@ -36,31 +262,6 @@ void CardGui::alternateRender(MTGCard * card, JQuad ** manaIcons, float x, float mFont->SetScale(scale); int color = card->getColor(); - points[0].x = -width/2; - points[0].y = -height/2 ; - points[1].x = width/2; - points[1].y = -height/2; - points[2].x = width/2; - points[2].y = height/2; - points[3].x = -width/2; - points[3].y = height/2; - - for (int i=0; i < 4; i++){ - points[i].x *= scale; - points[i].y *= scale; - points[i].Rotate(rotation); - } - - if (rotation == 0){ - renderer->FillRoundRect(x+points[0].x + 2 ,y+points[0].y +2 ,width*scale-8,height*scale-8,2,ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); - renderer->FillRect(x+points[0].x + 6 ,y+points[0].y + 6 ,width*scale-12,height*scale-12,bgcolor2); - }else{ - for (int i=0; i < 4; i++){ - renderer->DrawLine(x + points[i].x,y + points[i].y,x + points[(i+1)%4].x,y + points[(i+1)%4].y,bgcolor); - } - } - - ManaCost * manacost = card->getManaCost(); int nbicons = 0; ManaCostHybrid * h; @@ -110,77 +311,6 @@ void CardGui::alternateRender(MTGCard * card, JQuad ** manaIcons, float x, float mFont->DrawString(buf,x+v.x,y+v.y); } - if (!card->formattedTextInit){ - std::string s(card->getText()); - s = _(s); - std::string::size_type found=s.find_first_of("{}"); - while (found!=string::npos) - { - s[found]='/'; - found=s.find_first_of("{}",found+1); - } - std::string::size_type len = 24; - while (s.length() > 0){ - std::string::size_type cut = s.find_first_of("., \t)", 0); - if (cut >= len || cut == string::npos){ - card->formattedText.push_back(s.substr(0,len)); - if (s.length() > len){ - s = s.substr(len,s.length()-len); - }else{ - s = ""; - } - }else{ - std::string::size_type newcut = cut; - while (newcut < len && newcut != string::npos){ - cut = newcut; - newcut = s.find_first_of("., \t)", newcut + 1); - } - card->formattedText.push_back(s.substr(0,cut+1)); - if (s.length() > cut+1){ - s = s.substr(cut+1,s.length() - cut - 1); - }else{ - s = ""; - } - } - } - card->formattedTextInit = 1; - } - - - - for (std::vector::size_type i=0; i < card->formattedText.size(); i++){ - sprintf(buf, "%s", card->formattedText[i].c_str()); - v.x = (-width/2 + 12 )*scale; - v.y = (50 + static_cast(16*i - height/2)) * scale; - v.Rotate(rotation); - mFont->DrawString(buf,x+v.x,y+v.y); - } - - - - v.x = ((-width/2)+10) * scale; - v.y = ((-height/2) + 25) * scale; - v.Rotate(rotation); - int over = strlen(_(card->getName()).c_str()) - 23; - float multiply = 1.4; - if (over > 0){ - multiply = 1.1; - } - mFont->SetScale(scale * multiply); - - mFont->SetColor(ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); - mFont->DrawString(_(card->getName()).c_str(),x+v.x,y+v.y); - mFont->SetScale(scale); - mFont->SetColor(ARGB(255,255,255,255)); - - - if (card->isACreature()){ - v.x = (width/2-40) * scale; - v.y = (height/2-30) * scale; - v.Rotate(rotation); - sprintf(buf,"%i/%i",card->power,card->toughness); - mFont->DrawString(buf,x+v.x,y+v.y); - } for (int i = card->nb_types-1; i>=0; i--){ v.x = ((-width/2)+10) * scale; @@ -194,10 +324,13 @@ void CardGui::alternateRender(MTGCard * card, JQuad ** manaIcons, float x, float } -CardGui::CardGui(int id, MTGCardInstance * _card, float desiredHeight,float _x, float _y, bool hasFocus): PlayGuiObject(id, desiredHeight, _x, _y, hasFocus){ +CardGui::CardGui(int id, MTGCardInstance * _card, float desiredHeight, float x, float y, bool hasFocus): PlayGuiObject(id, desiredHeight, x, y, hasFocus){ LOG("==Creating NEW CardGui Object. CardName:"); LOG(_card->getName()); + actX = x; + actY = y; + card = _card; type = GUI_CARD; @@ -227,12 +360,12 @@ void CardGui::Update(float dt){ if (card->changedZoneRecently > 0) alpha = 255.f - 255.f * card->changedZoneRecently; if (mParticleSys && card->changedZoneRecently == 1.f){ - mParticleSys->MoveTo(x+15, y+2*mHeight/3); + mParticleSys->MoveTo(actX + 15, actY + 2 * mHeight / 3); mParticleSys->Fire(); } if (card->changedZoneRecently){ if (mParticleSys) mParticleSys->Update(dt); - card->changedZoneRecently-= (5 *dt); + card->changedZoneRecently-= (5 *dt); if (card->changedZoneRecently == 0) card->changedZoneRecently-= dt;//must not become zero atm if (card->changedZoneRecently < 0){ if (mParticleSys) mParticleSys->Stop(); @@ -242,31 +375,13 @@ void CardGui::Update(float dt){ mParticleSys = NULL; } } + + actX += 10 * dt * (x - actX); + actY += 10 * dt * (y - actY); + PlayGuiObject::Update(dt); } -void CardGui::RenderBig(float xpos, float ypos, int alternate){ - JQuad * quad = NULL; - JRenderer * renderer = JRenderer::GetInstance(); - if (xpos == -1){ - xpos = 300; - if (x > SCREEN_WIDTH / 2) - xpos = 10; - } - if(ypos == -1) - ypos = 20; - if (!alternate){ - quad = card->getQuad(); - if (quad){ - quad->SetColor(ARGB(220,255,255,255)); - float scale = 257.f / quad->mHeight; - renderer->RenderQuad(quad, xpos , ypos , 0.0f,scale,scale); - }else{ - quad = card->getThumb(); - alternate = 1; - } - } - if (alternate){ MTGCard * mtgcard = card->model; @@ -299,44 +414,36 @@ void CardGui::Render(){ float rotation = M_PI_2 * tap; float mScale = mHeight / 64; float myW = 45 * mScale; - float myH = 60*mScale; + float myH = 60 * mScale; GameObserver * game = GameObserver::GetInstance(); TargetChooser * tc = NULL; if (game) tc = game->getCurrentTargetChooser(); - float myX = x + (32 * tap * mScale); - float myY = y+(20 * tap * mScale); + float myX = actX + (32 * tap * mScale); + float myY = actY + (20 * tap * mScale); if (quad){ mScale = mHeight / quad->mHeight; myH = mHeight; myW = quad->mWidth * mScale; - myX = x + (quad->mHeight/2 * tap * mScale); - myY = y+(quad->mWidth/2 * tap * mScale); + myX = actX + (quad->mHeight/2 * tap * mScale); + myY = actY + (quad->mWidth/2 * tap * mScale); } if (mHeight-defaultHeight){ - if (card->isTapped()){ - renderer->FillRect(myX + 1*(mHeight-defaultHeight) - myH , myY + 1*(mHeight-defaultHeight) , myH, myW, ARGB(128,0,0,0)); - }else{ - renderer->FillRect(myX + 1*(mHeight-defaultHeight) , myY + 1*(mHeight-defaultHeight) , myW, myH, ARGB(128,0,0,0)); - } + if (card->isTapped()) + renderer->FillRect(myX + 1 * (mHeight - defaultHeight) - myH, myY + 1 * (mHeight - defaultHeight), myH, myW, ARGB(128,0,0,0)); + else + renderer->FillRect(myX + 1 * (mHeight - defaultHeight), myY + 1 * (mHeight-defaultHeight), myW, myH, ARGB(128,0,0,0)); } if(quad){ - quad->SetColor(ARGB( alpha,255,255,255)); + quad->SetColor(ARGB(alpha, 255, 255, 255)); - if (tc){ - if (!tc->canTarget(card)){ - quad->SetColor(ARGB( alpha,50,50,50)); - } - } - renderer->RenderQuad(quad, myX , myY , rotation,mScale,mScale); - quad->SetColor(ARGB( alpha,255,255,255)); + if (tc && !tc->canTarget(card)) quad->SetColor(ARGB(alpha, 50, 50, 50)); + renderer->RenderQuad(quad, myX, myY ,rotation, mScale, mScale); + quad->SetColor(ARGB(alpha, 255, 255, 255)); }else{ int color = card->getColor(); - - - char buffer[200]; sprintf(buffer, "%s",card->getName()); mFont->SetColor(ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); @@ -355,46 +462,39 @@ void CardGui::Render(){ } if (mIcon) mIcon->SetHotSpot(16,16); if (card->isTapped()){ - renderer->FillRect(myX - myH , myY , myH, myW, ARGB(255,(Constants::_r[color]) /2 + 50,(Constants::_g[color]) /2 + 50,(Constants::_b[color])/ 2 + 50)); - renderer->DrawRect(myX - myH , myY , myH, myW, ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); + renderer->FillRect(myX - myH, myY, myH, myW, ARGB(255,Constants::_r[color]/2+50,Constants::_g[color]/2+50,Constants::_b[color]/2+50)); + renderer->DrawRect(myX - myH, myY, myH, myW, ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); mFont->SetScale(DEFAULT_MAIN_FONT_SCALE * 0.8 * mScale); - mFont->DrawString(buffer,myX - myH + 4, myY + 1); - if (mIcon) renderer->RenderQuad(mIcon,myX - myH/2, myY + myW/2,M_PI_2,mScale,mScale); - if (tc){ - if (!tc->canTarget(card)){ - renderer->FillRect(myX - myH , myY , myH, myW, ARGB(200,0,0,0)); - } - } + mFont->DrawString(buffer, myX - (myH) + 4, myY + 1); + if (mIcon) renderer->RenderQuad(mIcon, myX - myH / 2,myY + myW / 2, M_PI_2, mScale, mScale); + if (tc && !tc->canTarget(card)) + renderer->FillRect(myX - myH, myY, myH, myW, ARGB(200,0,0,0)); }else{ - renderer->FillRect(myX , myY , myW, myH, ARGB(255,(Constants::_r[color]) /2 + 50,(Constants::_g[color]) /2 + 50,(Constants::_b[color]) /2 + 50)); - renderer->DrawRect(myX , myY , myW, myH, ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); + renderer->FillRect(myX, myY , myW, myH, ARGB(255,Constants::_r[color]/2+50,Constants::_g[color]/2+50,Constants::_b[color]/2+50)); + renderer->DrawRect(myX, myY , myW, myH, ARGB(255,Constants::_r[color],Constants::_g[color],Constants::_b[color])); mFont->SetScale(DEFAULT_MAIN_FONT_SCALE * 0.5 * mScale); - mFont->DrawString(buffer,myX+4,myY + 1); - if (mIcon) renderer->RenderQuad(mIcon,myX + myW/2, myY + myH/2,0,mScale, mScale); - if (tc){ - if (!tc->canTarget(card)){ - renderer->FillRect(myX , myY , myW, myH, ARGB(200,0,0,0)); - } - } + mFont->DrawString(buffer, myX + 4, myY + 1); + if (mIcon) renderer->RenderQuad(mIcon,myX + myW/2, myY + myH / 2, 0, mScale, mScale); + if (tc && !tc->canTarget(card)) + renderer->FillRect(myX, myY, myW, myH, ARGB(200,0,0,0)); } mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - } + } if (tc && tc->alreadyHasTarget(card)){ - if (card->isTapped()){ - renderer->FillRect(myX- myH , myY , myH, myW, ARGB(128,255,0,0)); - }else{ - renderer->FillRect(myX , myY , myW, myH, ARGB(128,255,0,0)); - } + if (card->isTapped()) + renderer->FillRect(myX - myH, myY, myH, myW, ARGB(128,255,0,0)); + else + renderer->FillRect(myX, myY, myW, myH, ARGB(128,255,0,0)); } - if (card->isACreature()){ + if (card->isCreature()){ mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); char buffer[200]; sprintf(buffer, "%i/%i",card->power,card->life); - renderer->FillRect(x+2,y + mHeight - 12, 25 , 12 ,ARGB(128,0,0,0)); + renderer->FillRect(actX + 2, actY + mHeight - 12, 25, 12, ARGB(128,0,0,0)); mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(buffer,x+4,y + mHeight - 10); + mFont->DrawString(buffer, actX + 4, actY + mHeight - 10); } if (mParticleSys && card->changedZoneRecently > 0){ @@ -403,17 +503,33 @@ void CardGui::Render(){ // set normal blending renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); } + + PlayGuiObject::Render(); } - +float CardGui::Height() +{ + return card->getQuad()->mHeight; +} +float CardGui::Width() +{ + return card->getQuad()->mWidth; +} CardGui::~CardGui(){ LOG("==Destroying CardGui object"); LOG(this->card->getName()); LOG("==CardGui object destruction Successful"); } +*/ +ostream& CardView::toString(ostream& out) const +{ + return (CardGui::toString(out) << " : CardView ::: card : " << card + << "; actX,actY : " << actX << "," << actY << "; t : " << t + << " ; actT : " << actT << " ; quad : " << quad); +} ostream& CardGui::toString(ostream& out) const { - return (out << "CardGui ::: mParticleSys : " << mParticleSys << " ; alpha : " << alpha << " ; card : " << card); + return (out << "CardGui ::: x,y " << x << "," << y); } diff --git a/projects/mtg/src/Credits.cpp b/projects/mtg/src/Credits.cpp index 71c09eab8..ddff97fde 100644 --- a/projects/mtg/src/Credits.cpp +++ b/projects/mtg/src/Credits.cpp @@ -41,12 +41,11 @@ void Credits::compute(Player * _p1, Player * _p2, GameApp * _app){ app = _app; showMsg = (rand() % 5); GameObserver * g = GameObserver::GetInstance(); - if (!p1->isAI() && p2->isAI() && p1!= g->gameOver){ - GameOptions * go = GameOptions::GetInstance(); + if (!p1->isAI() && p2->isAI() && p1!= g->gameOver){ value = 400; if (app->gameType != GAME_TYPE_CLASSIC) value = 200; - int difficulty = go->values[OPTIONS_DIFFICULTY].getIntValue(); - if (go->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED].getIntValue() && difficulty) { + int difficulty = options[Options::DIFFICULTY].number; + if (options[Options::DIFFICULTY_MODE_UNLOCKED].number && difficulty) { CreditBonus * b = NEW CreditBonus(100*difficulty, _("Difficulty Bonus")); bonus.push_back(b); } @@ -77,31 +76,31 @@ void Credits::compute(Player * _p1, Player * _p2, GameApp * _app){ if (unlocked){ unlockedTex = JRenderer::GetInstance()->LoadTexture("graphics/unlocked.png", TEX_TYPE_USE_VRAM); unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96); - GameOptions::GetInstance()->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED] = GameOption(1); - GameOptions::GetInstance()->save(); - }else if((unlocked = isMomirUnlocked())) { + options[Options::DIFFICULTY_MODE_UNLOCKED] = GameOption(1); + options.save(); + } else if ((unlocked = isMomirUnlocked())) { unlockedTex = JRenderer::GetInstance()->LoadTexture("graphics/momir_unlocked.png", TEX_TYPE_USE_VRAM); unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96); - GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED] = GameOption(1); - GameOptions::GetInstance()->save(); - }else if((unlocked = isEvilTwinUnlocked())) { + options[Options::MOMIR_MODE_UNLOCKED] = GameOption(1); + options.save(); + } else if ((unlocked = isEvilTwinUnlocked())) { unlockedTex = JRenderer::GetInstance()->LoadTexture("graphics/eviltwin_unlocked.png", TEX_TYPE_USE_VRAM); unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96); - GameOptions::GetInstance()->values[OPTIONS_EVILTWIN_MODE_UNLOCKED] = GameOption(1); - GameOptions::GetInstance()->save(); + options[Options::EVILTWIN_MODE_UNLOCKED] = GameOption(1); + options.save(); }else if((unlocked = isRandomDeckUnlocked())) { unlockedTex = JRenderer::GetInstance()->LoadTexture("graphics/randomdeck_unlocked.png", TEX_TYPE_USE_VRAM); unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96); - GameOptions::GetInstance()->values[OPTIONS_RANDOMDECK_MODE_UNLOCKED] = GameOption(1); - GameOptions::GetInstance()->save(); + options[Options::RANDOMDECK_MODE_UNLOCKED] = GameOption(1); + options.save(); }else if((unlocked = unlockRandomSet())) { unlockedTex = JRenderer::GetInstance()->LoadTexture("graphics/set_unlocked.png", TEX_TYPE_USE_VRAM); unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96); char buffer[4096]; unlockedString = MtgSets::SetsList->values[unlocked -1]; sprintf(buffer,"unlocked_%s", unlockedString.c_str()); - GameOptions::GetInstance()->values[buffer] = GameOption(1); - GameOptions::GetInstance()->save(); + options[buffer] = GameOption(1); + options.save(); } if (unlocked){ JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/bonus.wav"); @@ -113,9 +112,8 @@ void Credits::compute(Player * _p1, Player * _p2, GameApp * _app){ if (bonus.size()){ CreditBonus * b = NEW CreditBonus(value, _("Victory")); bonus.insert(bonus.begin(),b); - for ( it=bonus.begin()+1 ; it < bonus.end(); ++it){ - value+= (*it)->value; - } + for (it = bonus.begin() + 1; it < bonus.end(); ++it) + value += (*it)->value; } @@ -186,7 +184,7 @@ void Credits::Render(){ int Credits::isDifficultyUnlocked(){ - if (GameOptions::GetInstance()->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED].getIntValue()) return 0; + if (options[Options::DIFFICULTY_MODE_UNLOCKED].number) return 0; int nbAIDecks = 0; int found = 1; int wins = 0; @@ -210,20 +208,20 @@ int Credits::isDifficultyUnlocked(){ } int Credits::isMomirUnlocked(){ - if (GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()) return 0; + if (options[Options::MOMIR_MODE_UNLOCKED].number) return 0; if (p1->game->inPlay->countByType("land") == 8) return 1; return 0; } int Credits::isEvilTwinUnlocked(){ - if (GameOptions::GetInstance()->values[OPTIONS_EVILTWIN_MODE_UNLOCKED].getIntValue()) return 0; + if (options[Options::EVILTWIN_MODE_UNLOCKED].number) return 0; if (p1->game->inPlay->nb_cards && (p1->game->inPlay->nb_cards == p2->game->inPlay->nb_cards)) return 1; return 0; } int Credits::isRandomDeckUnlocked(){ - if (GameOptions::GetInstance()->values[OPTIONS_DIFFICULTY].getIntValue() == 0 ) return 0; - if (GameOptions::GetInstance()->values[OPTIONS_RANDOMDECK_MODE_UNLOCKED].getIntValue()) return 0; + if (0 == options[Options::DIFFICULTY].number) return 0; + if (options[Options::RANDOMDECK_MODE_UNLOCKED].number) return 0; if (p1->life >= 20 ) return 1; return 0; } @@ -234,6 +232,6 @@ int Credits::unlockRandomSet(){ char buffer[4096]; string s = MtgSets::SetsList->values[setId]; sprintf(buffer,"unlocked_%s", s.c_str()); - if (GameOptions::GetInstance()->values[buffer].getIntValue() == 1 ) return 0; - return setId+1; + if (1 == options[buffer].number) return 0; + return setId + 1; } diff --git a/projects/mtg/src/Damage.cpp b/projects/mtg/src/Damage.cpp index 43d69a79f..245e65a74 100644 --- a/projects/mtg/src/Damage.cpp +++ b/projects/mtg/src/Damage.cpp @@ -4,13 +4,14 @@ #include "../include/Counters.h" #include "../include/WEvent.h" #include "../include/Translate.h" +#include "../include/TexturesCache.h" -Damage::Damage(int id, MTGCardInstance * _source, Damageable * _target): Interruptible(id){ - init(_source, _target, _source->getPower()); +Damage::Damage(int id, MTGCardInstance * source, Damageable * target) { + init(source, target, source->getPower()); } -Damage::Damage(int id, MTGCardInstance * _source, Damageable * _target, int _damage): Interruptible(id){ - init(_source, _target, _damage); +Damage::Damage(int id, MTGCardInstance * source, Damageable * target, int damage) { + init(source, target, damage); } void Damage::init(MTGCardInstance * _source, Damageable * _target, int _damage){ @@ -68,7 +69,7 @@ void Damage::Render(){ sprintf(buffer, _("Deals %i damage to").c_str(), damage); mFont->DrawString(buffer, x + 20 , y, JGETEXT_LEFT); JRenderer * renderer = JRenderer::GetInstance(); - JQuad * quad = source->getThumb(); + JQuad * quad = cache.getThumb(source); if (quad){ float scale = 30 / quad->mHeight; renderer->RenderQuad(quad, x , y , 0,scale,scale); @@ -92,7 +93,7 @@ ostream& Damage::toString(ostream& out) const return out; } -DamageStack::DamageStack(int id, GameObserver * _game):GuiLayer(id, _game), Interruptible(id){ +DamageStack::DamageStack(GameObserver* game) : game(game){ currentState = -1; type = ACTION_DAMAGES; } diff --git a/projects/mtg/src/DamageResolverLayer.cpp b/projects/mtg/src/DamageResolverLayer.cpp index ae07c2ca7..2872d6c7c 100644 --- a/projects/mtg/src/DamageResolverLayer.cpp +++ b/projects/mtg/src/DamageResolverLayer.cpp @@ -6,7 +6,7 @@ #include "../include/Damage.h" #include "../include/Translate.h" -DamageResolverLayer::DamageResolverLayer(int id, GameObserver * _game):PlayGuiObjectController(id, _game){ +DamageResolverLayer::DamageResolverLayer(GameObserver * game) : game(game){ currentPhase = -1; remainingDamageSteps = 0; damageStack = NULL; @@ -106,9 +106,9 @@ DamagerDamaged * DamageResolverLayer::addIfNotExists(MTGCardInstance * card, Pla DamagerDamaged * item = (DamagerDamaged *)mObjects[i]; if (item->card == card) return item; } - CardGui * cardg = game->mLayers->playLayer()->getByCard(card); - DamagerDamaged * item = NEW DamagerDamaged(cardg, selecter, mCount == 0); - Add(item); + // CardGui * cardg = game->mLayers->playLayer()->getByCard(card); + DamagerDamaged * item = NEW DamagerDamaged(card, selecter, mCount == 0); + // Add(NEW TransientCardView(card->gui)); mCurr = 0; return item; } @@ -116,9 +116,11 @@ DamagerDamaged * DamageResolverLayer::addIfNotExists(MTGCardInstance * card, Pla void DamageResolverLayer::updateAllCoordinates(){ for (int i = 0; i < mCount; i++){ DamagerDamaged * item = (DamagerDamaged *)mObjects[i]; + /* CardGui * cardg = game->mLayers->playLayer()->getByCard(item->card); item->x = cardg->x; item->y = cardg->y; + */ } } @@ -129,9 +131,11 @@ int DamageResolverLayer::updateCoordinates(MTGCardInstance * card){ if (item->card != card) item = NULL ; } if (!item) return 0; + /* CardGui * cardg = game->mLayers->playLayer()->getByCard(card); item->x = cardg->x; item->y = cardg->y; + */ return 1; } @@ -181,7 +185,7 @@ int DamageResolverLayer::initResolve(){ #endif currentSource = NULL; currentChoosingPlayer = game->currentPlayer; - damageStack = NEW DamageStack(mCount,game); + damageStack = NEW DamageStack(game); int strike = 0; if (remainingDamageSteps == 2) strike = 1; @@ -436,7 +440,69 @@ bool DamageResolverLayer::CheckUserInput(u32 key){ }else if (PSP_CTRL_SQUARE == key){ return nextPlayer(); }else{ - return PlayGuiObjectController::CheckUserInput(key); + if (!mCount) + return false; + if (game != NULL){ + if (mActionButton == key){ + if (mObjects[mCurr] != NULL && mObjects[mCurr]->ButtonPressed()){ + game->ButtonPressed((PlayGuiObject *)mObjects[mCurr]); + return true; + } + } + if (PSP_CTRL_CROSS == key){ + game->cancelCurrentAction(); + return true; + } + } + + last_user_move = 0; + switch (key) + { + case PSP_CTRL_LEFT: + { + int n = getClosestItem(DIR_LEFT); + if (n != mCurr && mObjects[mCurr] != NULL && mObjects[mCurr]->Leaving(PSP_CTRL_LEFT)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + } + return true; + } + case PSP_CTRL_RIGHT: + { + int n = getClosestItem(DIR_RIGHT); + if (n != mCurr && mObjects[mCurr] != NULL && mObjects[mCurr]->Leaving(PSP_CTRL_RIGHT)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + } + return true; + } + case PSP_CTRL_UP: + { + int n = getClosestItem(DIR_UP); + if (n != mCurr && mObjects[mCurr] != NULL && mObjects[mCurr]->Leaving(PSP_CTRL_UP)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + } + return true; + } + case PSP_CTRL_DOWN: + { + int n = getClosestItem(DIR_DOWN); + if (n != mCurr && mObjects[mCurr] != NULL && mObjects[mCurr]->Leaving(PSP_CTRL_DOWN)) + { + mCurr = n; + mObjects[mCurr]->Entering(); + } + return true; + } + case PSP_CTRL_TRIANGLE: + showBigCards = (showBigCards + 1) % 3; + return true; + } + return false; } return false; } @@ -455,7 +521,7 @@ void DamageResolverLayer::Render(){ mFont->DrawString(_("Blocking Player").c_str(), 0,0); } if (currentSource){ - currentSource->RenderBig(10, 20); + // currentSource->RenderBig(10, 20); mFont->DrawString(_("Current Damager:").c_str(), 10, 5); } for (int i = 0; i < mCount; i++){ diff --git a/projects/mtg/src/DamagerDamaged.cpp b/projects/mtg/src/DamagerDamaged.cpp index d3e16c6a5..aff5dbcaf 100644 --- a/projects/mtg/src/DamagerDamaged.cpp +++ b/projects/mtg/src/DamagerDamaged.cpp @@ -6,7 +6,7 @@ Temporary objects that store the damages dealt to/from creatures during the comb */ -DamagerDamaged::DamagerDamaged(CardGui * cardg, Player * _damageSelecter, bool _hasFocus):CardGui(0, cardg->card,cardg->defaultHeight,cardg->x,cardg->y, _hasFocus){ +DamagerDamaged::DamagerDamaged(MTGCardInstance* card, Player * _damageSelecter, bool _hasFocus) : card(card){ mCount = 0; damageSelecter = _damageSelecter; damageToDeal = card->power; @@ -37,7 +37,7 @@ int DamagerDamaged::dealOneDamage(DamagerDamaged * target){ damageToDeal--; #if defined (WIN32) || defined (LINUX) char buf[4096]; - sprintf(buf, "==========\n%s can still deal %i damages\n=============\n", card->getName(), damageToDeal); + sprintf(buf, "==========\n%s can still deal %i damages\n=============\n", card->getName().c_str(), damageToDeal); OutputDebugString(buf); #endif return target->addDamage(1, this); @@ -76,9 +76,10 @@ int DamagerDamaged::removeDamagesFrom(DamagerDamaged * source){ void DamagerDamaged::Render(Player * currentPlayer){ JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MAIN_FONT); mFont->SetBase(0); - CardGui::Render(); + // CardGui::Render(); char buf[4096]; + /* if (currentPlayer != damageSelecter){ if (hasLethalDamage()){ mFont->DrawString("X",x,y); @@ -92,4 +93,5 @@ void DamagerDamaged::Render(Player * currentPlayer){ mFont->DrawString(buf,x+5, y+5); } mFont->SetColor(ARGB(255,255,255,255)); + */ } diff --git a/projects/mtg/src/DuelLayers.cpp b/projects/mtg/src/DuelLayers.cpp index dd40464cd..66bf01947 100644 --- a/projects/mtg/src/DuelLayers.cpp +++ b/projects/mtg/src/DuelLayers.cpp @@ -1,65 +1,146 @@ #include "../include/config.h" #include "../include/DuelLayers.h" #include "../include/MTGRules.h" -#include "../include/DamageResolverLayer.h" +#include "../include/GuiCombat.h" +#include "../include/GuiBackground.h" +#include "../include/GuiFrame.h" #include "../include/GuiPhaseBar.h" - +#include "../include/GuiAvatars.h" +#include "../include/GuiHand.h" +#include "../include/GuiPlay.h" +#include "../include/GuiMana.h" void DuelLayers::init(){ + GameObserver* go = GameObserver::GetInstance(); - //0 Stack Layer - ActionStack * mActionStack = NEW ActionStack(0, GameObserver::GetInstance()); - - //Damage Resolver - DamageResolverLayer * mDamageResolver = NEW DamageResolverLayer(1, GameObserver::GetInstance()); - + cs = NEW CardSelector(this); //1 Action Layer - GuiLayer * actionLayer = NEW ActionLayer(2, GameObserver::GetInstance()); - MTGGamePhase * phaseManager = NEW MTGGamePhase(actionLayer->getMaxId()); - actionLayer->Add(phaseManager); + action = NEW ActionLayer(); + action->Add(NEW MTGGamePhase(action->getMaxId())); //Add Magic Specific Rules - actionLayer->Add(NEW MTGPutInPlayRule(-1)); - actionLayer->Add(NEW MTGAttackRule(-1)); - actionLayer->Add(NEW MTGBlockRule(-1)); - actionLayer->Add(NEW MTGLegendRule(-1)); - actionLayer->Add(NEW MTGPersistRule(-1)); - actionLayer->Add(NEW MTGLifelinkRule(-1)); + action->Add(NEW MTGPutInPlayRule(-1)); + action->Add(NEW MTGAttackRule(-1)); + action->Add(NEW MTGBlockRule(-1)); + action->Add(NEW MTGLegendRule(-1)); + action->Add(NEW MTGPersistRule(-1)); + action->Add(NEW MTGLifelinkRule(-1)); //Other display elements - actionLayer->Add(NEW HUDDisplay(-1)); + action->Add(NEW HUDDisplay(-1)); - //2 Hand Layer - MTGGuiHand * mGuiHand = NEW MTGGuiHand(3, GameObserver::GetInstance()); + Add(NEW GuiMana()); + Add(stack = NEW ActionStack(go)); + Add(combat = NEW GuiCombat(cs)); + Add(action); + Add(cs); + Add(hand = NEW GuiHandSelf(cs, go->players[0]->game->hand)); + Add(NEW GuiHandOpponent(cs, go->players[1]->game->hand)); + Add(NEW GuiPlay(go, cs)); - //3 Game - MTGGuiPlay * play = NEW MTGGuiPlay(4, GameObserver::GetInstance()); - - //Add(NEW GuiPhaseBar(GameObserver::GetInstance())); - Add(mActionStack); - Add(mDamageResolver); - Add(actionLayer); - Add(mGuiHand); - Add(play); + Add(NEW GuiAvatars(cs)); + Add(NEW GuiPhaseBar()); + Add(NEW GuiFrame()); + Add(NEW GuiBackground()); } +void DuelLayers::Update(float dt, Player * currentPlayer) +{ + for (int i = 0; i < nbitems; ++i) objects[i]->Update(dt); + int isAI = currentPlayer->isAI(); + u32 key; + GameObserver * game = GameObserver::GetInstance(); + while ((key = JGE::GetInstance()->ReadButton())){ + if ((!isAI) && (0 != key)) + { + if (stack->CheckUserInput(key)) break; + // if (combat->CheckUserInput(key)) break; + if (action->CheckUserInput(key)) break; + if (hand->CheckUserInput(key)) break; + if (cs->CheckUserInput(key)) break; + } + } + if (isAI) currentPlayer->Act(dt); +} ActionStack * DuelLayers::stackLayer(){ - return ((ActionStack *) (objects[0])); -} - -DamageResolverLayer * DuelLayers::combatLayer(){ - return ((DamageResolverLayer *) (objects[1])); + return stack; } ActionLayer * DuelLayers::actionLayer(){ - return ((ActionLayer *) (objects[2])); + return action; } -MTGGuiHand * DuelLayers::handLayer(){ - return ((MTGGuiHand *) (objects[3])); -} -MTGGuiPlay * DuelLayers::playLayer(){ - return ((MTGGuiPlay *) (objects[4])); +DuelLayers::DuelLayers() : nbitems(0) {} + +DuelLayers::~DuelLayers(){ + for (int i = 0; i < nbitems; ++i) delete objects[i]; } +int DuelLayers::unstoppableRenderInProgress(){ + for (int i = 0; i < nbitems; ++i) + if (objects[i]->unstoppableRenderInProgress()) + return 1; + return 0; +} +void DuelLayers::Add(GuiLayer * layer){ + objects.push_back(layer); + nbitems++; +} + +void DuelLayers::Remove(){ + --nbitems; +} + +void DuelLayers::Render(){ + bool focusMakesItThrough = true; + for (int i = 0; i < nbitems; ++i) + { + objects[i]->hasFocus = focusMakesItThrough; + if (objects[i]->modal) focusMakesItThrough = false; + } + for (int i = nbitems - 1; i >= 0; --i) + objects[i]->Render(); +} + +int DuelLayers::receiveEvent(WEvent * e){ + +#if 0 +#define PRINT_IF(type) { type *foo = dynamic_cast(e); if (foo) cout << "Is a " << #type << endl; } + cout << "Received event " << e << endl; + PRINT_IF(WEventZoneChange); + PRINT_IF(WEventDamage); + PRINT_IF(WEventPhaseChange); + PRINT_IF(WEventCardUpdate); + PRINT_IF(WEventCardTap); + PRINT_IF(WEventCreatureAttacker); + PRINT_IF(WEventCreatureBlocker); + PRINT_IF(WEventCreatureBlockerRank); + PRINT_IF(WEventEngageMana); + PRINT_IF(WEventConsumeMana); +#endif + + int used = 0; + for (int i = 0; i < nbitems; ++i) + used |= objects[i]->receiveEventPlus(e); + if (!used) + { + Pos* p; + if (WEventZoneChange *event = dynamic_cast(e)) + { + if (event->card->view) + waiters.push_back(p = new Pos(*(event->card->view))); + else + waiters.push_back(p = new Pos(0, 0, 0, 0, 255)); + event->card->view = p; + } + } + for (int i = 0; i < nbitems; ++i) + objects[i]->receiveEventMinus(e); + return 1; +} + +float DuelLayers::RightBoundary() +{ + return hand->LeftBoundary(); +} diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index a05fa15a8..bd5d6b371 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -24,6 +24,8 @@ int GameApp::HasMusic = 1; JMusic * GameApp::music = NULL; string GameApp::systemError = ""; +JQuad* manaIcons[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + GameState::GameState(GameApp* parent): mParent(parent) { mEngine = JGE::GetInstance(); @@ -64,19 +66,15 @@ void GameApp::Create() //Test for Music files presence std::ifstream file(RESPATH"/sound/Track0.mp3"); - if(file){ + if (file) file.close(); - }else{ + else HasMusic = 0; - } std::ifstream file2(RESPATH"/sound/Track1.mp3"); - if(file2){ + if (file2) file2.close(); - }else{ + else HasMusic = 0; - } - - CommonRes->CreateTexture("graphics/menuicons.png"); //Creating thes quad in this specific order allows us to have them in the correct order to call them by integer id @@ -87,6 +85,14 @@ void GameApp::Create() CommonRes->CreateQuad("c_black", "graphics/menuicons.png", 2 + 2*36, 38, 32, 32); CommonRes->CreateQuad("c_white", "graphics/menuicons.png", 2 + 4*36, 38, 32, 32); CommonRes->CreateQuad("c_land", "graphics/menuicons.png", 2 + 5*36, 38, 32, 32); + manaIcons[Constants::MTG_COLOR_ARTIFACT] = GameApp::CommonRes->GetQuad("c_artifact"); + manaIcons[Constants::MTG_COLOR_LAND] = GameApp::CommonRes->GetQuad("c_land"); + manaIcons[Constants::MTG_COLOR_WHITE] = GameApp::CommonRes->GetQuad("c_white"); + manaIcons[Constants::MTG_COLOR_RED] = GameApp::CommonRes->GetQuad("c_red"); + manaIcons[Constants::MTG_COLOR_BLACK] = GameApp::CommonRes->GetQuad("c_black"); + manaIcons[Constants::MTG_COLOR_BLUE] = GameApp::CommonRes->GetQuad("c_blue"); + manaIcons[Constants::MTG_COLOR_GREEN] = GameApp::CommonRes->GetQuad("c_green"); + for (int i = sizeof(manaIcons)/sizeof(manaIcons[0]) - 1; i >= 0; --i) manaIcons[i]->SetHotSpot(16,16); CommonRes->CreateTexture("sets/back.jpg"); @@ -108,9 +114,54 @@ void GameApp::Create() CommonRes->CreateTexture("graphics/phasebar.png"); - CommonRes->CreateTexture("graphics/background.png"); + CommonRes->CreateTexture("graphics/wood.png"); + CommonRes->CreateTexture("graphics/gold.png"); + CommonRes->CreateTexture("graphics/goldglow.png"); CommonRes->CreateTexture("graphics/back.jpg"); - CommonRes->CreateTexture("graphics/phasebar.png"); + + CommonRes->CreateTexture("graphics/handback.png"); + + CommonRes->CreateTexture("sets/red.jpg"); + CommonRes->CreateTexture("sets/white.jpg"); + CommonRes->CreateTexture("sets/blue.jpg"); + CommonRes->CreateTexture("sets/black.jpg"); + CommonRes->CreateTexture("sets/green.jpg"); + CommonRes->CreateQuad("red", "sets/red.jpg", 0, 0, 200, 285); + CommonRes->CreateQuad("white", "sets/white.jpg", 0, 0, 200, 285); + CommonRes->CreateQuad("blue", "sets/blue.jpg", 0, 0, 200, 285); + CommonRes->CreateQuad("black", "sets/black.jpg", 0, 0, 200, 285); + CommonRes->CreateQuad("green", "sets/green.jpg", 0, 0, 200, 285); + CommonRes->GetQuad("red")->SetHotSpot(100, 145); + CommonRes->GetQuad("white")->SetHotSpot(100, 145); + CommonRes->GetQuad("blue")->SetHotSpot(100, 145); + CommonRes->GetQuad("black")->SetHotSpot(100, 145); + CommonRes->GetQuad("green")->SetHotSpot(100, 145); + + CommonRes->CreateTexture("sets/red_thumb.jpg"); + CommonRes->CreateTexture("sets/white_thumb.jpg"); + CommonRes->CreateTexture("sets/blue_thumb.jpg"); + CommonRes->CreateTexture("sets/black_thumb.jpg"); + CommonRes->CreateTexture("sets/green_thumb.jpg"); + CommonRes->CreateQuad("red_thumb", "sets/red_thumb.jpg", 0, 0, 28, 40); + CommonRes->CreateQuad("white_thumb", "sets/white_thumb.jpg", 0, 0, 28, 40); + CommonRes->CreateQuad("blue_thumb", "sets/blue_thumb.jpg", 0, 0, 28, 40); + CommonRes->CreateQuad("black_thumb", "sets/black_thumb.jpg", 0, 0, 28, 40); + CommonRes->CreateQuad("green_thumb", "sets/green_thumb.jpg", 0, 0, 28, 40); + CommonRes->GetQuad("red_thumb")->SetHotSpot(14, 20); + CommonRes->GetQuad("white_thumb")->SetHotSpot(14, 20); + CommonRes->GetQuad("blue_thumb")->SetHotSpot(14, 20); + CommonRes->GetQuad("black_thumb")->SetHotSpot(14, 20); + CommonRes->GetQuad("green_thumb")->SetHotSpot(14, 20); + + CommonRes->CreateTexture("graphics/BattleIcon.png"); + CommonRes->CreateTexture("graphics/DefenderIcon.png"); + CommonRes->CreateTexture("graphics/shadow.png"); + CommonRes->CreateQuad("BattleIcon", "graphics/BattleIcon.png", 0, 0, 25, 25); + CommonRes->CreateQuad("DefenderIcon", "graphics/DefenderIcon.png", 0, 0, 24, 23); + CommonRes->CreateQuad("shadow", "graphics/shadow.png", 0, 0, 1, 1); + CommonRes->GetQuad("BattleIcon")->SetHotSpot(12, 12); + CommonRes->GetQuad("DefenderIcon")->SetHotSpot(12, 12); + CommonRes->GetQuad("shadow")->SetHotSpot(0.5, 0.5); //CommonRes->CreateTexture("graphics/interrupt.png"); //CommonRes->CreateQuad("interrupt", "graphics/interrupt.png", 0, 0, 256, 128); @@ -188,8 +239,6 @@ void GameApp::Destroy() SAFE_DELETE(CommonRes); - GameOptions::Destroy(); //No delete ??? - SAFE_DELETE(Subtypes::subtypesList); SAFE_DELETE(MtgSets::SetsList); diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index ba06a02d5..f86c1892c 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -88,10 +88,12 @@ void GameObserver::nextGamePhase(){ Phase * cPhaseOld = phaseRing->getCurrentPhase(); if (!blockersSorted && cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS){ blockersAssigned = 1; + /* if (!mLayers->combatLayer()->autoOrderBlockers()){ OutputDebugString("Player has To choose ordering!"); return; } + */ } phaseRing->forward(); @@ -149,18 +151,20 @@ int GameObserver::cancelCurrentAction(){ void GameObserver::userRequestNextGamePhase(){ if (mLayers->stackLayer()->getNext(NULL,0,NOT_RESOLVED)) return; if (getCurrentTargetChooser()) return; - if (mLayers->combatLayer()->isDisplayed()) return; + // if (mLayers->combatLayer()->isDisplayed()) return; Phase * cPhaseOld = phaseRing->getCurrentPhase(); if (!blockersSorted && cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS){ blockersAssigned = 1; + /* if (!mLayers->combatLayer()->autoOrderBlockers()){ OutputDebugString("Player has To choose ordering!"); return; } + */ } - if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS || - opponent()->isAI() || - GameOptions::GetInstance()->values[GameOptions::phaseInterrupts[currentGamePhase]].getIntValue()){ + if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS || + opponent()->isAI() || + options[GameOptions::phaseInterrupts[currentGamePhase]].number){ mLayers->stackLayer()->AddNextGamePhase(); }else{ nextGamePhase(); @@ -170,30 +174,31 @@ void GameObserver::userRequestNextGamePhase(){ int GameObserver::forceShuffleLibraries(){ OutputDebugString("FORCING\n"); int result = 0; - for (int i=0; i<2; i++){ - if (forceShuffleLibrary[i]) { - forceShuffleLibrary[i] = 0; - players[i]->game->library->shuffle(); - result++; - OutputDebugString("YAY\n"); + if (players[0]->game->library->needShuffle) + { + players[0]->game->library->shuffle(); + players[0]->game->library->needShuffle = false; + ++result; + } + if (players[1]->game->library->needShuffle) + { + players[1]->game->library->shuffle(); + players[1]->game->library->needShuffle = false; + ++result; } - } - if (result) mLayers->playLayer()->forceUpdateCards(); return result; } void GameObserver::startGame(int shuffle, int draw){ int i; - for (i=0; igame->initGame(shuffle, draw); - forceShuffleLibrary[i] = 0; - } //Preload images from hand if (!players[0]->isAI()){ for (i=0; i< players[0]->game->hand->nb_cards; i++){ - players[0]->game->hand->cards[i]->getThumb(); - players[0]->game->hand->cards[i]->getQuad(); + cache.getThumb(players[0]->game->hand->cards[i]); + cache.getQuad(players[0]->game->hand->cards[i]); } } turn = 0; @@ -202,9 +207,8 @@ void GameObserver::startGame(int shuffle, int draw){ //Difficult mode special stuff if (!players[0]->isAI() && players[1]->isAI()){ - GameOptions * go = GameOptions::GetInstance(); - int difficulty = go->values[OPTIONS_DIFFICULTY].getIntValue(); - if (go->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED].getIntValue() && difficulty) { + int difficulty = options[Options::DIFFICULTY].number; + if (options[Options::DIFFICULTY_MODE_UNLOCKED].number && difficulty) { Player * p = players[1]; for (int level=0; level < difficulty; level ++){ MTGCardInstance * card = NULL; @@ -218,7 +222,7 @@ void GameObserver::startGame(int shuffle, int draw){ } if (card){ MTGCardInstance * copy = p->game->putInZone(card, p->game->library, p->game->stack); - Spell * spell = NEW Spell(copy); + Spell * spell = NEW Spell(copy); spell->resolve(); delete spell; } @@ -259,8 +263,8 @@ void GameObserver::Update(float dt){ if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS && !blockersSorted){ player = opponent(); }else if (currentGamePhase == Constants::MTG_PHASE_COMBATDAMAGE){ - DamageResolverLayer * drl = mLayers->combatLayer(); - if (drl->currentChoosingPlayer && drl->mCount) player = drl->currentChoosingPlayer; + // DamageResolverLayer * drl = mLayers->combatLayer(); + // if (drl->currentChoosingPlayer && drl->mCount) player = drl->currentChoosingPlayer; } currentActionPlayer = player; if (isInterrupting) player = isInterrupting; @@ -309,39 +313,33 @@ void GameObserver::Render(){ -void GameObserver::ButtonPressed (int controllerId, PlayGuiObject * _object){ +void GameObserver::ButtonPressed(PlayGuiObject * target){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Click\n"); #endif - int id = _object->GetId(); - if (id >=0){ - MTGCardInstance * card = ((CardGui *)_object)->card; + if (CardView* cardview = dynamic_cast(target)){ + MTGCardInstance * card = cardview->getCard(); cardClick(card, card); } - if (id== -6 || id == -4){ //libraries - GuiGameZone * zone = (GuiGameZone *)_object; - if (zone->showCards){ - zone->toggleDisplay(); + else if (GuiLibrary* library = dynamic_cast(target)){ + if (library->showCards){ + library->toggleDisplay(); forceShuffleLibraries(); } else { - int pId = (-id - 4)/2; TargetChooser * _tc = this->getCurrentTargetChooser(); - if (_tc && _tc->targetsZone(players[pId]->game->library)){ - zone->toggleDisplay(); - forceShuffleLibrary[pId] = 1; + if (_tc && _tc->targetsZone(library->zone)){ + library->toggleDisplay(); + library->zone->needShuffle = true; } } - } - if (id== -5 || id == -3){ - GuiGameZone * zone = (GuiGameZone *)_object; - zone->toggleDisplay(); - } - if (id == -1 || id == -2){ + else if (GuiGraveyard* graveyard = dynamic_cast(target)) + graveyard->toggleDisplay(); + else if (GuiAvatar* avatar = dynamic_cast(target)){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Click Player !\n"); #endif - cardClick(NULL, ((GuiAvatar *)_object)->player); + cardClick(NULL, avatar->player); } } @@ -468,8 +466,8 @@ int GameObserver::receiveEvent(WEvent * e){ } -int GameObserver::isACreature(MTGCardInstance * card){ - return card->isACreature(); +bool GameObserver::isCreature(MTGCardInstance * card){ + return card->isCreature(); } diff --git a/projects/mtg/src/GameOptions.cpp b/projects/mtg/src/GameOptions.cpp index 0a9a87260..dbdb603e4 100644 --- a/projects/mtg/src/GameOptions.cpp +++ b/projects/mtg/src/GameOptions.cpp @@ -22,22 +22,24 @@ const char* GameOptions::phaseInterrupts[] = { "interrupt Cleanup", "interrupt ---" }; +const string Options::MUSICVOLUME = "musicVolume"; +const string Options::SFXVOLUME = "sfxVolume"; +const string Options::DIFFICULTY_MODE_UNLOCKED = "prx_handler"; //huhu +const string Options::MOMIR_MODE_UNLOCKED = "prx_rimom"; //haha +const string Options::DIFFICULTY = "difficulty"; +const string Options::CACHESIZE = "cacheSize"; +const string Options::PLASMAEFFECT = "plasmaEffect"; +const string Options::INTERRUPT_SECONDS = "interruptSeconds"; +const string Options::INTERRUPTMYSPELLS = "interruptMySpells"; +const string Options::INTERRUPTMYABILITIES = "interruptMyAbilities"; +const string Options::EVILTWIN_MODE_UNLOCKED = "prx_eviltwin"; +const string Options::RANDOMDECK_MODE_UNLOCKED = "prx_rnddeck"; +const string Options::OSD = "displayOSD"; -GameOption::GameOption(int _value){ - value = _value; -} -int GameOption::getIntValue(){ - return value; -} -GameOptions* GameOptions::mInstance = NULL; - -GameOptions * GameOptions::GetInstance(){ - if (mInstance == NULL) - mInstance = NEW GameOptions(); - return mInstance; -} +GameOption::GameOption(int value) : number(value){} +GameOption::GameOption(string value) : str(value){} GameOptions::GameOptions(){ load(); @@ -63,7 +65,7 @@ int GameOptions::save(){ if (file){ map::iterator it; for ( it=values.begin() ; it != values.end(); it++ ){ - sprintf(writer,"%s=%d\n", it->first.c_str(), it->second.getIntValue()); + sprintf(writer,"%s=%d\n", it->first.c_str(), it->second.number); file<GetJLBFont(Constants::MENU_FONT); - mFont->SetBase(0); + mFont->SetBase(0); opponentMenuFont = mFont; @@ -116,7 +116,7 @@ void GameStateDuel::loadPlayerRandom(int playerId, int isAI, int mode){ int nbcolors = 3; string lands[] = {"forest", "forest", "island", "mountain", "swamp", "plains", "forest"}; - + MTGDeck * tempDeck = NEW MTGDeck(NULL, mParent->collection); tempDeck->addRandomCards(9,0,0,-1,lands[color1].c_str()); @@ -129,15 +129,14 @@ void GameStateDuel::loadPlayerRandom(int playerId, int isAI, int mode){ tempDeck->addRandomCards(2,0,0,-1,"instant",colors,nbcolors); tempDeck->addRandomCards(2,0,0,-1,"artifact",colors,nbcolors); - char * deckFile = "random"; + string deckFile = "random"; string deckFileSmall = "random"; - deck[playerId] = NEW MTGPlayerCards(mParent->collection,tempDeck); - if (!isAI){ //Human Player - mPlayers[playerId] = NEW HumanPlayer(deck[playerId],deckFile, deckFileSmall); - }else{ - mPlayers[playerId] = NEW AIPlayerBaka(deck[playerId],deckFile, deckFileSmall.c_str() , ""); - } + deck[playerId] = NEW MTGPlayerCards(mParent->collection, tempDeck); + if (!isAI) // Human Player + mPlayers[playerId] = NEW HumanPlayer(deck[playerId], deckFile, deckFileSmall); + else + mPlayers[playerId] = NEW AIPlayerBaka(deck[playerId],deckFile, deckFileSmall, ""); delete tempDeck; } @@ -147,12 +146,11 @@ void GameStateDuel::loadPlayerMomir(int playerId, int isAI){ string deckFileSmall = "momir"; char empty[] = ""; MTGDeck * tempDeck = NEW MTGDeck(deckFile, NULL, mParent->collection); - deck[playerId] = NEW MTGPlayerCards(mParent->collection,tempDeck); - if (!isAI){ //Human Player - mPlayers[playerId] = NEW HumanPlayer(deck[playerId],deckFile, deckFileSmall); - }else{ - mPlayers[playerId] = NEW AIMomirPlayer(deck[playerId],deckFile,deckFileSmall.c_str(), empty); - } + deck[playerId] = NEW MTGPlayerCards(mParent->collection, tempDeck); + if (!isAI) // Human Player + mPlayers[playerId] = NEW HumanPlayer(deck[playerId], deckFile, deckFileSmall); + else + mPlayers[playerId] = NEW AIMomirPlayer(deck[playerId], deckFile, deckFileSmall, empty); delete tempDeck; } @@ -295,17 +293,15 @@ void GameStateDuel::Update(float dt) else deckmenu->Update(dt); break; case DUEL_STATE_CHOOSE_DECK2: - if (mParent->players[1] == PLAYER_TYPE_HUMAN){ + if (mParent->players[1] == PLAYER_TYPE_HUMAN) deckmenu->Update(dt); - } else{ if (mParent->players[0] == PLAYER_TYPE_HUMAN){ if (!opponentMenu){ opponentMenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_OPPONENT, this, opponentMenuFont, 35, 25, "Choose Opponent"); opponentMenu->Add(0,"Random"); - if (GameOptions::GetInstance()->values[OPTIONS_EVILTWIN_MODE_UNLOCKED].getIntValue()){ - opponentMenu->Add(-1,"Evil Twin", "Can you play against yourself?"); - } + if (options[Options::EVILTWIN_MODE_UNLOCKED].number) + opponentMenu->Add(-1,"Evil Twin", "Can you play against yourself?"); fillDeckMenu(opponentMenu,RESPATH"/ai/baka", "ai_baka", mPlayers[0]); } opponentMenu->Update(dt); @@ -457,7 +453,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) break; } case DUEL_MENU_CHOOSE_DECK: - { + { if (controlId < 0){ mParent->SetNextState(GAME_STATE_DECK_VIEWER); return; diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index ae8e5d6ca..7813e835b 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -5,7 +5,7 @@ #include "../include/GameOptions.h" #include "../include/GameApp.h" #include "../include/MTGCard.h" -#include "../include/Translate.h" +#include "../include/Translate.h" #include "../include/DeckStats.h" #include "../include/PlayerData.h" #include "../include/utils.h" @@ -148,23 +148,19 @@ void GameStateMenu::Start(){ JRenderer::GetInstance()->EnableVSync(true); subMenuController = NULL; - if (GameApp::HasMusic && !GameApp::music && GameOptions::GetInstance()->values[OPTIONS_MUSICVOLUME].getIntValue() > 0){ + if (GameApp::HasMusic && !GameApp::music && options[Options::MUSICVOLUME].number > 0){ GameApp::music = JSoundSystem::GetInstance()->LoadMusic("sound/Track0.mp3"); JSoundSystem::GetInstance()->PlayMusic(GameApp::music, true); } - if (GameApp::HasMusic && GameApp::music && GameOptions::GetInstance()->values[OPTIONS_MUSICVOLUME].getIntValue() == 0){ + if (GameApp::HasMusic && GameApp::music && options[Options::MUSICVOLUME].number == 0){ JSoundSystem::GetInstance()->StopMusic(GameApp::music); SAFE_DELETE(GameApp::music); } hasChosenGameType = 1; - if (GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()) hasChosenGameType =0; - if (GameOptions::GetInstance()->values[OPTIONS_RANDOMDECK_MODE_UNLOCKED].getIntValue()) hasChosenGameType =0; - - - - + if (options[Options::MOMIR_MODE_UNLOCKED].number) hasChosenGameType = 0; + if (options[Options::RANDOMDECK_MODE_UNLOCKED].number) hasChosenGameType = 0; } @@ -175,7 +171,7 @@ void GameStateMenu::fillScroller(){ DeckStats * stats = DeckStats::GetInstance(); int totalGames = 0; - + for (int j=1; j<6; j++){ sprintf(buffer, RESPATH"/player/stats/player_deck%i.txt",j); if(fileExists(buffer)){ @@ -194,28 +190,26 @@ void GameStateMenu::fillScroller(){ sprintf(buff2, _("You have played a total of %i games").c_str(),totalGames); scroller->Add(buff2); } - - GameOptions * go = GameOptions::GetInstance(); - if (!go->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED].getIntValue()){ - scroller->Add(_("Unlock the difficult mode for more challenging duels!")); - } - if (!go->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()){ - scroller->Add(_("Interested in playing Momir Basic? You'll have to unlock it first :)")); - } - if (!go->values[OPTIONS_RANDOMDECK_MODE_UNLOCKED].getIntValue()){ - scroller->Add(_("You haven't unlocked the random deck mode yet")); - } - if (!go->values[OPTIONS_EVILTWIN_MODE_UNLOCKED].getIntValue()){ - scroller->Add(_("You haven't unlocked the evil twin mode yet")); - } + if (!options[Options::DIFFICULTY_MODE_UNLOCKED].number) + scroller->Add(_("Unlock the difficult mode for more challenging duels!")); + if (!options[Options::MOMIR_MODE_UNLOCKED].number) + scroller->Add(_("Interested in playing Momir Basic? You'll have to unlock it first :)")); + if (!options[Options::RANDOMDECK_MODE_UNLOCKED].number) + scroller->Add(_("You haven't locked the random deck mode yet")); + if (!options[Options::EVILTWIN_MODE_UNLOCKED].number) + scroller->Add(_("You haven't unlocked the evil twin mode yet")); + if (!options[Options::RANDOMDECK_MODE_UNLOCKED].number) + scroller->Add(_("You haven't unlocked the random deck mode yet")); + if (!options[Options::EVILTWIN_MODE_UNLOCKED].number) + scroller->Add(_("You haven't unlocked the evil twin mode yet")); //Unlocked sets int nbunlocked = 0; for (int i = 0; i < MtgSets::SetsList->nb_items; i++){ string s = MtgSets::SetsList->values[i]; sprintf(buffer,"unlocked_%s", s.c_str()); - if (GameOptions::GetInstance()->values[buffer].getIntValue() == 1 ) nbunlocked++; + if (1 == options[buffer].number) nbunlocked++; } sprintf(buff2, _("You have unlocked %i expansions out of %i").c_str(),nbunlocked, MtgSets::SetsList->nb_items); scroller->Add(buff2); @@ -323,20 +317,16 @@ void GameStateMenu::Update(float dt) string s = MtgSets::SetsList->values[setId]; char buffer[4096]; sprintf(buffer,"unlocked_%s", s.c_str()); - GameOptions::GetInstance()->values[buffer] = GameOption(1); - GameOptions::GetInstance()->save(); - - createUsersFirstDeck(setId); + options[buffer] = GameOption(1); + options.save(); + createUsersFirstDeck(setId); } currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_NONE; break; case MENU_STATE_MAJOR_MAINMENU : if (!scrollerSet) fillScroller(); - if (mGuiController!=NULL){ + if (NULL != mGuiController) mGuiController->Update(dt); - } - - break; case MENU_STATE_MAJOR_SUBMENU : subMenuController->Update(dt); @@ -345,25 +335,24 @@ void GameStateMenu::Update(float dt) case MENU_STATE_MAJOR_DUEL : if (MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR)) { - if (!hasChosenGameType){ - currentState = MENU_STATE_MAJOR_SUBMENU; - JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MENU_FONT); - subMenuController = NEW SimpleMenu(102, this, mFont, 150,60); + if (!hasChosenGameType){ + currentState = MENU_STATE_MAJOR_SUBMENU; + JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MENU_FONT); + subMenuController = NEW SimpleMenu(102, this, mFont, 150,60); if (subMenuController){ subMenuController->Add(SUBMENUITEM_CLASSIC,"Classic"); - if (GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()){ - subMenuController->Add(SUBMENUITEM_MOMIR, "Momir Basic"); - } - if (GameOptions::GetInstance()->values[OPTIONS_RANDOMDECK_MODE_UNLOCKED].getIntValue()){ - subMenuController->Add(SUBMENUITEM_RANDOM1, "Random 1 Color"); - subMenuController->Add(SUBMENUITEM_RANDOM2, "Random 2 Colors"); - } + if (options[Options::MOMIR_MODE_UNLOCKED].number) + subMenuController->Add(SUBMENUITEM_MOMIR, "Momir Basic"); + if (options[Options::RANDOMDECK_MODE_UNLOCKED].number){ + subMenuController->Add(SUBMENUITEM_RANDOM1, "Random 1 Color"); + subMenuController->Add(SUBMENUITEM_RANDOM2, "Random 2 Colors"); + } subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel"); - } - }else{ + } + }else{ mParent->SetNextState(GAME_STATE_DUEL); currentState = MENU_STATE_MAJOR_MAINMENU; - } + } } } switch (MENU_STATE_MINOR & currentState) @@ -484,7 +473,7 @@ void GameStateMenu::Render() if (yW < 2*SCREEN_HEIGHT) renderer->RenderQuad(mMovingW, SCREEN_WIDTH/2 - 10, yW, angleW); if (mGuiController!=NULL) mGuiController->Render(); - + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); mFont->SetColor(ARGB(128,255,255,255)); mFont->DrawString(GAME_VERSION, SCREEN_WIDTH-10,5,JGETEXT_RIGHT); diff --git a/projects/mtg/src/GameStateOptions.cpp b/projects/mtg/src/GameStateOptions.cpp index f14c47e6f..4331c030b 100644 --- a/projects/mtg/src/GameStateOptions.cpp +++ b/projects/mtg/src/GameStateOptions.cpp @@ -25,23 +25,20 @@ void GameStateOptions::Start() JRenderer::GetInstance()->EnableVSync(true); optionsList = NEW OptionsList(); - if (GameApp::HasMusic) optionsList->Add(NEW OptionItem(OPTIONS_MUSICVOLUME, "Music volume", 100, 10)); - optionsList->Add(NEW OptionItem(OPTIONS_SFXVOLUME, "SFX volume", 100, 10)); - optionsList->Add(NEW OptionItem(OPTIONS_INTERRUPTMYSPELLS, "interrupt my spells")); - optionsList->Add(NEW OptionItem(OPTIONS_INTERRUPTMYABILITIES, "interrupt my abilities")); - optionsList->Add(NEW OptionItem(OPTIONS_OSD, "Display InGame extra information")); - // WALDORF - added next line - optionsList->Add(NEW OptionItem(OPTIONS_INTERRUPT_SECONDS, "Seconds to pause for an Interrupt", 20, 1)); - if (GameOptions::GetInstance()->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED].getIntValue()) { - optionsList->Add(NEW OptionItem(OPTIONS_DIFFICULTY, "Difficulty", 3, 1)); - } - optionsList->Add(NEW OptionItem(OPTIONS_CACHESIZE, "Image Cache Size", 60, 5)); + if (GameApp::HasMusic) optionsList->Add(NEW OptionItem(Options::MUSICVOLUME, "Music volume", 100, 10)); + optionsList->Add(NEW OptionItem(Options::SFXVOLUME, "SFX volume", 100, 10)); + optionsList->Add(NEW OptionItem(Options::INTERRUPTMYSPELLS, "interrupt my spells")); + optionsList->Add(NEW OptionItem(Options::INTERRUPTMYABILITIES, "interrupt my abilities")); + optionsList->Add(NEW OptionItem(Options::INTERRUPT_SECONDS, "Seconds to pause for an Interrupt", 20, 1)); + optionsList->Add(NEW OptionItem(Options::OSD, "Display InGame extra information")); + if (options[Options::DIFFICULTY_MODE_UNLOCKED].number) + optionsList->Add(NEW OptionItem(Options::DIFFICULTY, "Difficulty", 3, 1)); + optionsList->Add(NEW OptionItem(Options::CACHESIZE, "Image Cache Size", 60, 5)); JLBFont * mFont = GameApp::CommonRes->GetJLBFont("graphics/f3"); optionsMenu = NEW SimpleMenu(102, this,mFont, 50,170); optionsMenu->Add(1, "Save & Back to Main Menu"); optionsMenu->Add(2, "Back to Main Menu"); optionsMenu->Add(3, "Cancel"); - } diff --git a/projects/mtg/src/GameStateShop.cpp b/projects/mtg/src/GameStateShop.cpp index 793837f96..48273920c 100644 --- a/projects/mtg/src/GameStateShop.cpp +++ b/projects/mtg/src/GameStateShop.cpp @@ -67,22 +67,21 @@ void GameStateShop::load(){ if (s.compare("10E") == 0) defaultSet = i; char buffer[4096]; sprintf(buffer,"unlocked_%s", s.c_str()); - unlocked[i] = GameOptions::GetInstance()->values[buffer].getIntValue(); - if ( unlocked[i] ){ + unlocked[i] = options[buffer].number; + if (unlocked[i]) ok = 1; - } } if (!ok){ unlocked[defaultSet] = 1; string s = MtgSets::SetsList->values[defaultSet]; char buffer[4096]; sprintf(buffer,"unlocked_%s", s.c_str()); - GameOptions::GetInstance()->values[buffer] = GameOption(1); - GameOptions::GetInstance()->save(); + options[buffer] = GameOption(1); + options.save(); } for (int i = 0; i < MtgSets::SetsList->nb_items; i++){ - if (unlocked[i] ){ + if (unlocked[i]){ sets[nbsets] = i; nbsets++; if (mParent->collection->countBySet(i) > 80){ //Only sets with more than 80 cards can get boosters and starters diff --git a/projects/mtg/src/GuiLayers.cpp b/projects/mtg/src/GuiLayers.cpp index 6677457f0..4f02c8c25 100644 --- a/projects/mtg/src/GuiLayers.cpp +++ b/projects/mtg/src/GuiLayers.cpp @@ -2,9 +2,7 @@ #include "../include/GuiLayers.h" #include "../include/Player.h" -GuiLayer::GuiLayer(int id, GameObserver* _game){ - mId = id; - game = _game; +GuiLayer::GuiLayer(){ modal = 0; hasFocus = false; mCount = 0; @@ -42,7 +40,7 @@ int GuiLayer::getMaxId(){ void GuiLayer::Render(){ for (int i=0;iRender(); + mObjects[i]->Render(); } void GuiLayer::Update(float dt){ @@ -103,77 +101,3 @@ JGuiObject * GuiLayer::getByIndex(int index){ return mObjects[index]; } - -GuiLayers::GuiLayers(){ - nbitems = 0; -} - -GuiLayers::~GuiLayers(){ - LOG("==Destroying GuiLayers=="); - for (int i=0; iunstoppableRenderInProgress()) - return 1; - } - return 0; -} - - - -void GuiLayers::Add(GuiLayer * layer){ - if (nbitems >=MAX_GUI_LAYERS || nbitems < 0){ - LOG("OUT OF BOUND IN GuiLayers Add !!!"); - return; - } - objects[nbitems] = layer; - nbitems++; -} - -void GuiLayers::Remove(){ - nbitems --; -} - -void GuiLayers::Update(float dt, Player * currentPlayer){ - - for (int i=0; iUpdate(dt); - } - int isAI = currentPlayer->isAI(); - u32 key; - while ((key = JGE::GetInstance()->ReadButton())){ - for (int i=0; iCheckUserInput(key)) break; - } - } - } - if (isAI) currentPlayer->Act(dt); - -} - -void GuiLayers::Render(){ - bool focusMakesItThrough = true; - for (int i = 0; i < nbitems; ++i) - { - objects[i]->hasFocus = focusMakesItThrough; - if (objects[i]->modal) focusMakesItThrough = false; - } - for (int i=nbitems-1; i>=0; i--){ - objects[i]->Render(); - } -} - - -int GuiLayers::receiveEvent(WEvent * e){ - for (int i = 0; i < nbitems; i++){ - objects[i]->receiveEvent(e); - } - return 1; -} - diff --git a/projects/mtg/src/GuiPhaseBar.cpp b/projects/mtg/src/GuiPhaseBar.cpp index 706e46d89..55f0eb0bb 100644 --- a/projects/mtg/src/GuiPhaseBar.cpp +++ b/projects/mtg/src/GuiPhaseBar.cpp @@ -18,7 +18,7 @@ static int colors[] = ARGB(255, 255, 255, 255) }; -GuiPhaseBar::GuiPhaseBar(GameObserver* game):GuiLayer(0,game), phase(GameObserver::GetInstance()->phaseRing->getCurrentPhase()), angle(0.0f) +GuiPhaseBar::GuiPhaseBar() : phase(GameObserver::GetInstance()->phaseRing->getCurrentPhase()), angle(0.0f) { JTexture* texture = GameApp::CommonRes->GetTexture("graphics/phasebar.png"); if (texture) @@ -45,24 +45,24 @@ void GuiPhaseBar::Render() static const float ICONSCALE = 1.5; static const unsigned CENTER = SCREEN_HEIGHT / 2 + 10; JRenderer* renderer = JRenderer::GetInstance(); - unsigned p = (phase->id + Phases - 4) * Width; + unsigned p = (phase->id + Phases - 4) * (Width+1); float scale; float start = CENTER + (Width / 2) * angle * ICONSCALE / (M_PI / 6) - ICONSCALE * Width / 4; renderer->DrawLine(0, CENTER, SCREEN_WIDTH, CENTER, ARGB(255, 255, 255, 255)); scale = ICONSCALE * sinf(angle + 3 * M_PI / 6) / 2; - quad->SetTextureRect((p + 3 * Width) % (Phases * Width), 0, Width, Height); + quad->SetTextureRect((p + 3 * (Width+1)) % (Phases * (Width+1)), 0, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); start += Width * scale; scale = ICONSCALE * sinf(angle + 4 * M_PI / 6) / 2; - quad->SetTextureRect((p + 4 * Width) % (Phases * Width), Height, Width, Height); + quad->SetTextureRect((p + 4 * (Width+1)) % (Phases * (Width+1)), Height, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); start += Width * scale; scale = ICONSCALE * sinf(angle + 5 * M_PI / 6) / 2; - quad->SetTextureRect((p + 5 * Width) % (Phases * Width), Height, Width, Height); + quad->SetTextureRect((p + 5 * (Width+1)) % (Phases * (Width+1)), Height, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); start += Width * scale; @@ -70,25 +70,24 @@ void GuiPhaseBar::Render() scale = ICONSCALE * sinf(angle + 2 * M_PI / 6) / 2; start -= Width * scale; - quad->SetTextureRect((p + 2 * Width) % (Phases * Width), Height, Width, Height); + quad->SetTextureRect((p + 2 * (Width+1)) % (Phases * (Width+1)), Height, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); scale = ICONSCALE * sinf(angle + 1 * M_PI / 6) / 2; start -= Width * scale; - quad->SetTextureRect((p + 1 * Width) % (Phases * Width), Height, Width, Height); + quad->SetTextureRect((p + 1 * (Width+1)) % (Phases * (Width+1)), Height, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); if (angle > 0) { scale = ICONSCALE * sinf(angle)/2; start -= Width * scale; - quad->SetTextureRect(p % (Phases * Width), Height, Width, Height); + quad->SetTextureRect(p % (Phases * (Width+1)), Height, Width, Height); renderer->RenderQuad(quad, 0, start, 0.0, scale, scale); } } - -int GuiPhaseBar::receiveEvent(WEvent *e) +int GuiPhaseBar::receiveEventMinus(WEvent *e) { WEventPhaseChange *event = dynamic_cast(e); if (event) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index bb544abc9..c818ffbae 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1311,7 +1311,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ game->mLayers->stackLayer()->addDamage(card, game->players[i], x); for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->basicAbilities[Constants::FLYING] && current->isACreature()){ + if (current->basicAbilities[Constants::FLYING] && current->isCreature()){ game->mLayers->stackLayer()->addDamage(card, current, x); } } @@ -1348,7 +1348,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ game->mLayers->stackLayer()->addDamage(card, game->players[i], x); for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->isACreature()){ + if (current->isCreature()){ game->mLayers->stackLayer()->addDamage(card, current, x); } } @@ -1372,13 +1372,13 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ { int x = computeX(spell,card); for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], x); - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (!current->basicAbilities[Constants::FLYING] && current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, x); - } - } + game->mLayers->stackLayer()->addDamage(card, game->players[i], x); + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (!current->basicAbilities[Constants::FLYING] && current->isCreature()){ + game->mLayers->stackLayer()->addDamage(card, current, x); + } + } } break; } @@ -2286,69 +2286,79 @@ other solutions need to be provided for abilities that add mana (ex: mana flare) */ - AManaProducer::AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost , int doTap):MTGAbility(id, card), tap(doTap){ +AManaProducer::AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost , int doTap):MTGAbility(id, card), tap(doTap){ - LOG("==Creating ManaProducer Object"); - aType=MTGAbility::MANA_PRODUCER; - cost = _cost; - output=_output; - x1 = 10; - y1 = 220; - Player * player = card->controller(); - if (player == game->players[1]) y1 = 100; - x = x1; - y = y1; - animation = 0.f; - mParticleSys = NULL; - menutext = ""; + LOG("==Creating ManaProducer Object"); + aType = MTGAbility::MANA_PRODUCER; + cost = _cost; + output = _output; + cout << "!" << card->view << endl; + if (card->view) + { + x1 = card->view->actX; y1 = card->view->actY; + } + else + { + x1 = 10; y1 = 220; + } + Player * player = card->controller(); + if (player == game->players[1]) y1 = 100; + x = x1; + y = y1; + animation = 0.f; + mParticleSys = NULL; + menutext = ""; - int landColor = output->getMainColor(); + int landColor = output->getMainColor(); - if (landColor == Constants::MTG_COLOR_RED){ + switch (landColor) + { + case Constants::MTG_COLOR_RED : mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_BLUE){ + break; + case Constants::MTG_COLOR_BLUE : mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_GREEN){ + break; + case Constants::MTG_COLOR_GREEN : mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_BLACK){ + break; + case Constants::MTG_COLOR_BLACK : mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_WHITE){ + break; + case Constants::MTG_COLOR_WHITE : mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); - }else{ + break; + default : mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); } + LOG("==ManaProducer Object Creation successful !"); +} - - LOG("==ManaProducer Object Creation successful !"); - } - - void AManaProducer::Update(float dt){ - if (mParticleSys) mParticleSys->Update(dt); - if (animation){ - x = (1.f - animation)*x1 + animation * x0; - y = (1.f - animation)*y1 + animation * y0; - if (mParticleSys) mParticleSys->MoveTo(x, y); - if (mParticleSys && animation == 1.f) mParticleSys->Fire(); - animation -= 4 *dt; - if (!animation) animation = -1; - if (animation < 0){ - resolve(); - } +void AManaProducer::Update(float dt){ + if (mParticleSys) mParticleSys->Update(dt); + if (animation){ + x = (1.f - animation)*x1 + animation * x0; + y = (1.f - animation)*y1 + animation * y0; + if (mParticleSys) mParticleSys->MoveTo(x, y); + if (mParticleSys && animation == 1.f) mParticleSys->Fire(); + animation -= 4 *dt; + if (!animation) animation = -1; + if (animation < 0){ + resolve(); } - } +} - void AManaProducer::Render(){ - JRenderer * renderer = JRenderer::GetInstance(); - if (animation){ - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); - if (mParticleSys) mParticleSys->Render(); - // set normal blending - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); - } - +void AManaProducer::Render(){ + JRenderer * renderer = JRenderer::GetInstance(); + if (animation){ + // renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); + // if (mParticleSys) mParticleSys->Render(); + // set normal blending + // renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); } +} int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana){ int result = 0; @@ -2387,17 +2397,21 @@ other solutions need to be provided for abilities that add mana (ex: mana flare) currentlyTapping++; animation = 1.f; - CardGui * cardg = game->mLayers->playLayer()->getByCard(source); - if (cardg){ - x0 = cardg->x + 15; - y0 = cardg->y + 20; - } - - if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME].getIntValue() > 0 && currentlyTapping < 3){ + if (options[Options::SFXVOLUME].number > 0 && currentlyTapping < 3){ JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/mana.wav"); if (sample) JSoundSystem::GetInstance()->PlaySample(sample); } + + for (int i = Constants::MTG_NB_COLORS - 2; i >= 1; --i) + { + for (int cost = output->getCost(i); cost > 0; --cost) + { + WEventEngageMana e(i, source); + GameObserver::GetInstance()->receiveEvent(&e); + } + } + return 1; } diff --git a/projects/mtg/src/MTGCard.cpp b/projects/mtg/src/MTGCard.cpp index 68eaf96d6..c169209f2 100644 --- a/projects/mtg/src/MTGCard.cpp +++ b/projects/mtg/src/MTGCard.cpp @@ -3,14 +3,15 @@ //------------------------------------------------- //TODO Fill BasicAbilities -#include "../include/config.h" -#include "../include/MTGCard.h" - -#include "../include/TexturesCache.h" -#include "../include/Subtypes.h" - #include #include + +#include "../include/MTGDeck.h" +#include "../include/config.h" +#include "../include/MTGCard.h" +#include "../include/Subtypes.h" +#include "../include/Translate.h" + using std::string; @@ -18,12 +19,10 @@ const char * const MTGCard::Colors_To_Text[] = {"Artifact", "Green", "Blue", "Re MTGCard::MTGCard(){ init(); - mCache = NULL; } -MTGCard::MTGCard(TexturesCache * cache, int set_id){ +MTGCard::MTGCard(int set_id){ init(); - mCache = cache; setId = set_id; } @@ -32,7 +31,6 @@ const char * MTGCard::getSetName(){ } MTGCard::MTGCard(MTGCard * source){ - mCache = source->mCache; for(map::const_iterator it = source->basicAbilities.begin(); it != source->basicAbilities.end(); ++it){ basicAbilities[it->first] = source->basicAbilities[it->first]; } @@ -55,7 +53,6 @@ MTGCard::MTGCard(MTGCard * source){ toughness = source->toughness; mtgid = source->mtgid; setId = source->setId; - formattedTextInit = 0; magicText = source->magicText; spellTargetType = source->spellTargetType; alias = source->alias; @@ -72,34 +69,63 @@ int MTGCard::init(){ colors[i] = 0; } setId = 0; - formattedTextInit = 0; magicText = ""; spellTargetType = ""; alias = 0; return 1; } -JQuad * MTGCard::getQuad(int type){ - if (mCache == NULL){ - return NULL; - } - return mCache->getQuad(this, type); +const vector& MTGCard::formattedText() +{ + if (ftdText.empty()) + { + std::string s = _(text); + std::string::size_type found = s.find_first_of("{}"); + while (found!=string::npos) + { + s[found] = '/'; + found = s.find_first_of("{}", found + 1); + } + std::string::size_type len = 30; + while (s.length() > 0) + { + std::string::size_type cut = s.find_first_of("., \t)", 0); + if (cut >= len || cut == string::npos) + { + ftdText.push_back(s.substr(0,len)); + if (s.length() > len) + s = s.substr(len, s.length() - len); + else + s = ""; + } + else + { + std::string::size_type newcut = cut; + while (newcut < len && newcut != string::npos) + { + cut = newcut; + newcut = s.find_first_of("., \t)", newcut + 1); + } + ftdText.push_back(s.substr(0,cut+1)); + if (s.length() > cut+1) + s = s.substr(cut+1,s.length() - cut - 1); + else + s = ""; + } + } + } + return ftdText; } -JQuad * MTGCard::getThumb(){ - return getQuad(CACHE_THUMB); +bool MTGCard::isCreature(){ + return hasSubtype("creature"); } - -JQuad * MTGCard::getQuad(TexturesCache * cache){ - - return cache->getQuad(this); +bool MTGCard::isLand(){ + return hasSubtype("land"); } - - - -int MTGCard::isACreature(){ - return (hasSubtype("creature")); +bool MTGCard::isSpell(){ + return (!isCreature() && !isLand()); } void MTGCard::setColor(int _color, int removeAllOthers){ @@ -234,51 +260,45 @@ void MTGCard::setName( string value){ name = value; //This is a bug fix for plague rats and the "foreach ability" //Right now we add names as types, so that they get recognized - if (value.at(value.length()-1) == 's') Subtypes::subtypesList->Add(value); + if (value.at(value.length()-1) == 's') Subtypes::subtypesList->Add(value); } -const char * MTGCard::getName(){ - return name.c_str(); +const string MTGCard::getName() const{ + return name; } -ManaCost * MTGCard::getManaCost(){ +ManaCost* MTGCard::getManaCost(){ return &manaCost; } -int MTGCard::hasType(int _type){ - int i; - - - for (i = 0; iAdd(_type); - return(hasType(id)); + return hasType(id); } -int MTGCard::hasSubtype(const char * _subtype){ +bool MTGCard::hasSubtype(const char * _subtype){ int id = Subtypes::subtypesList->Add(_subtype); - return(hasType(id)); + return hasType(id); } -int MTGCard::hasSubtype(string _subtype){ +bool MTGCard::hasSubtype(string _subtype){ int id = Subtypes::subtypesList->Add(_subtype); - return(hasType(id)); + return hasType(id); } @@ -304,4 +324,3 @@ void MTGCard::setToughness(int _toughness){ int MTGCard::getToughness(){ return toughness; } - diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index ea3a0ce0c..acd24623e 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -12,24 +12,24 @@ #include using namespace std; -MTGCardInstance::MTGCardInstance(): MTGCard(), Damageable(0){ +MTGCardInstance::MTGCardInstance(): MTGCard(), Damageable(0), view(NULL){ LOG("==Creating MTGCardInstance=="); initMTGCI(); LOG("==Creating MTGCardInstance Successful=="); } -MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * _belongs_to): MTGCard(card), Damageable(card->getToughness()){ +MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to): MTGCard(card), Damageable(card->getToughness()), view(NULL){ LOG("==Creating MTGCardInstance=="); initMTGCI(); model = card; attacker = 0; lifeOrig = life; - belongs_to=_belongs_to; + belongs_to = arg_belongs_to; owner = NULL; - if (_belongs_to) owner = _belongs_to->library->owner; + if (arg_belongs_to) owner = arg_belongs_to->library->owner; lastController = owner; defenser = NULL; banding = NULL; - life=toughness; + life = toughness; LOG("==Creating MTGCardInstance Successful=="); } @@ -60,10 +60,9 @@ void MTGCardInstance::copy(MTGCardInstance * card){ lifeOrig = life; //mtgid = source->mtgid; //setId = source->setId; - formattedTextInit = 0; magicText = source->magicText; spellTargetType = source->spellTargetType; - alias = source->alias; + alias = source->alias; //Now this is dirty... int backupid = mtgid; @@ -109,7 +108,7 @@ void MTGCardInstance::initMTGCI(){ } -const char * MTGCardInstance::getDisplayName(){ +const string MTGCardInstance::getDisplayName(){ return getName(); } @@ -135,7 +134,7 @@ int MTGCardInstance::isInPlay(){ int MTGCardInstance::afterDamage(){ if (!doDamageTest) return 0; doDamageTest = 0; - if (!isACreature()) return 0; + if (!isCreature()) return 0; if (life <=0 && isInPlay()){ return destroy(); } @@ -168,10 +167,6 @@ MTGGameZone * MTGCardInstance::getCurrentZone(){ return NULL; } -JQuad * MTGCardInstance::getIcon(){ - return getThumb(); -} - int MTGCardInstance::has(int basicAbility){ return basicAbilities[basicAbility]; } @@ -271,16 +266,16 @@ return previous->stillInUse(); } /* Summoning Sickness - * 212.3f A creaturefs activated ability with the tap symbol or the untap symbol in its activation cost - * canft be played unless the creature has been under its controllerfs control since the start of his or - * her most recent turn. A creature canft attack unless it has been under its controllerfs control - * since the start of his or her most recent turn. This rule is informally called the gsummoning - * sicknessh rule. Ignore this rule for creatures with haste (see rule 502.5). + * 212.3f A creature's activated ability with the tap symbol or the untap symbol in its activation cost + * can't be played unless the creature has been under its controller's control since the start of his or + * her most recent turn. A creature can't attack unless it has been under its controller's control + * since the start of his or her most recent turn. This rule is informally called the "summoning + * sickness" rule. Ignore this rule for creatures with haste (see rule 502.5). */ int MTGCardInstance::hasSummoningSickness(){ if (!summoningSickness) return 0; if (basicAbilities[Constants::HASTE]) return 0; - if (!isACreature()) return 0; + if (!isCreature()) return 0; return 1; } @@ -318,7 +313,7 @@ int MTGCardInstance::canAttack(){ if (tapped) return 0; if (hasSummoningSickness()) return 0; if (basicAbilities[Constants::DEFENSER] || basicAbilities[Constants::CANTATTACK]) return 0; - if (!isACreature()) return 0; + if (!isCreature()) return 0; if (!isInPlay()) return 0; return 1; } @@ -341,7 +336,7 @@ int MTGCardInstance::setToughness(int value){ int MTGCardInstance::canBlock(){ if (tapped) return 0; if (basicAbilities[Constants::CANTBLOCK]) return 0; - if (!isACreature())return 0; + if (!isCreature()) return 0; if (!isInPlay()) return 0; return 1; } @@ -410,7 +405,7 @@ int MTGCardInstance::setAttacker(int value){ Targetable * target = NULL; Player * p = controller()->opponent(); if (value) target = p; - if (attacker) previousTarget = p; + if (attacker) previousTarget = p; attacker = value; WEvent * e = NEW WEventCreatureAttacker(this,previousTarget, target); GameObserver::GetInstance()->receiveEvent(e); @@ -421,7 +416,7 @@ int MTGCardInstance::setAttacker(int value){ int MTGCardInstance::toggleAttacker(){ if (!attacker){ if (!basicAbilities[Constants::VIGILANCE]) tap(); - setAttacker(1); + setAttacker(1); return 1; }else{ //Banding needs to be debugged... @@ -472,15 +467,15 @@ MTGCardInstance * MTGCardInstance::getNextDefenser(MTGCardInstance * previous){ } int MTGCardInstance::moveBlockerInRow(MTGCardInstance * blocker){ - list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); - list::iterator it2 = it1; - if (it2 == blockers.end()) it2 = blockers.begin(); else ++it2; - if (it2 == blockers.end()) it2 = blockers.begin(); - - std::iter_swap(it1,it2); - WEvent* e = NEW WEventCreatureBlockerRank(blocker,*it2,this); - GameObserver::GetInstance()->receiveEvent(e); - delete(e); + list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); + list::iterator it2 = it1; + if (it2 == blockers.end()) it2 = blockers.begin(); else ++it2; + if (it2 == blockers.end()) it2 = blockers.begin(); + + std::iter_swap(it1,it2); + WEvent* e = NEW WEventCreatureBlockerRank(blocker,*it2,this); + GameObserver::GetInstance()->receiveEvent(e); + delete(e); return 1; } diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index c4653965e..6c07f6ce9 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -275,7 +275,7 @@ int MTGAllCards::readConfLine(std::ifstream &file, int set_id){ switch(conf_read_mode) { case 0: if (s[0] == '['){ - tempCard = NEW MTGCard(mCache,set_id); + tempCard = NEW MTGCard(set_id); conf_read_mode = 1; } break; diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index 86472a13e..38c844c56 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -14,7 +14,6 @@ //------------------------------ MTGPlayerCards::MTGPlayerCards(MTGAllCards * _collection, int * idList, int idListSize){ - init(); int i; collection = _collection; @@ -25,14 +24,9 @@ MTGPlayerCards::MTGPlayerCards(MTGAllCards * _collection, int * idList, int idLi library->addCard(newCard); } } - - - } - - -MTGPlayerCards::MTGPlayerCards(MTGAllCards * _collection,MTGDeck * deck){ +MTGPlayerCards::MTGPlayerCards(MTGAllCards * _collection, MTGDeck * deck){ init(); collection = _collection; map::iterator it; @@ -70,7 +64,7 @@ void MTGPlayerCards::setOwner(Player * player){ void MTGPlayerCards::initGame(int shuffle, int draw){ if (shuffle) library->shuffle(); if (draw){ - for (int i=0;i<7;i++){ + for (int i=0;i<7;i++){ OutputDebugString("draw\n"); drawFromLibrary(); } @@ -153,10 +147,9 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone } if ((copy = from->removeCard(card,doCopy))){ - - if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME].getIntValue() > 0){ + if (options[Options::SFXVOLUME].number > 0){ if (to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard){ - if (card->isACreature()){ + if (card->isCreature()){ JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/graveyard.wav"); if (sample) JSoundSystem::GetInstance()->PlaySample(sample); } @@ -170,7 +163,7 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone ret = NULL; } } - + to->addCard(copy); copy->changedZoneRecently = 1.f; GameObserver *g = GameObserver::GetInstance(); @@ -200,9 +193,7 @@ int MTGPlayerCards::isInPlay(MTGCardInstance * card){ // Zones specific code //-------------------------------------- -MTGGameZone::MTGGameZone(){ - nb_cards= 0; - lastCardDrawn = NULL; +MTGGameZone::MTGGameZone() : nb_cards(0), lastCardDrawn(NULL), needShuffle(false) { } MTGGameZone::~MTGGameZone(){ @@ -227,13 +218,13 @@ MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy nb_cards--; cards.erase(cards.begin()+i); MTGCardInstance * copy = card; - if (card->isToken){ //TODO better than this ? + if (card->isToken) //TODO better than this ? return card; - } //card->lastController = card->controller(); if (createCopy) { copy = NEW MTGCardInstance(card->model,card->owner->game); copy->previous = card; + copy->view = card->view; card->next = copy; } copy->previousZone = this; @@ -313,11 +304,8 @@ MTGCardInstance * MTGLibrary::draw(){ } void MTGGameZone::debugPrint(){ - int i; - for (i=0;igetName()); - } + for (int i = 0; i < nb_cards; i++) + std::cerr << cards[i]->getName() << endl; } diff --git a/projects/mtg/src/MTGGuiHand.cpp b/projects/mtg/src/MTGGuiHand.cpp index ba4a46d57..08f77963d 100644 --- a/projects/mtg/src/MTGGuiHand.cpp +++ b/projects/mtg/src/MTGGuiHand.cpp @@ -2,7 +2,7 @@ #include "../include/MTGGuiHand.h" #include "../include/CardGui.h" -MTGGuiHand::MTGGuiHand(int id, GameObserver * _game):GuiCardsController(id, _game){ +MTGGuiHand::MTGGuiHand(GameObserver* game) : game(game) { mShowHand = HAND_HIDE; mAnimState = 0; currentPlayer = NULL; @@ -22,7 +22,7 @@ void MTGGuiHand::updateCards(){ resetObjects(); if (currentId[player->getId()] >= nb_cards) currentId[player->getId()] = nb_cards - 1; for (int i = 0;igame->hand->cards[i],(float)40, (float)450 - (nb_cards-i) *35, SCREEN_HEIGHT_F - mAnimState*60, i == currentId[player->getId()]); + CardView* object = NEW CardView(player->game->hand->cards[i], (float)450 - (nb_cards-i) *35, SCREEN_HEIGHT_F - mAnimState*60); Add(object); if ( i == currentId[player->getId()]) mCurr = i; } @@ -37,7 +37,7 @@ void MTGGuiHand::Update(float dt){ updateCards(); for (int i=0;iy= SCREEN_HEIGHT - mAnimState*60; + ((CardGui *)mObjects[i])->y = SCREEN_HEIGHT - mAnimState*60; } } @@ -79,7 +79,7 @@ bool MTGGuiHand::CheckUserInput(u32 key){ if (mShowHand == HAND_HIDE || currentPlayer->isAI()){ return false; }else{ - GuiCardsController::CheckUserInput(key); + // GuiCardsController::CheckUserInput(key); return true; } } @@ -98,7 +98,7 @@ void MTGGuiHand::Render(){ } if (mCount && mObjects[mCurr] != NULL){ mObjects[mCurr]->Render(); - if (showBigCards) ((CardGui *)mObjects[mCurr])->RenderBig(10,-1,showBigCards-1); + // if (showBigCards) ((CardGui *)mObjects[mCurr])->RenderBig(10,-1,showBigCards-1); } } } diff --git a/projects/mtg/src/MTGGuiPlay.cpp b/projects/mtg/src/MTGGuiPlay.cpp index a76d58568..f4e7198d3 100644 --- a/projects/mtg/src/MTGGuiPlay.cpp +++ b/projects/mtg/src/MTGGuiPlay.cpp @@ -23,7 +23,7 @@ -MTGGuiPlay::MTGGuiPlay(int id, GameObserver * _game):PlayGuiObjectController(id, _game){ +MTGGuiPlay::MTGGuiPlay(GameObserver* game) : game(game){ currentPlayer = NULL; offset = 0; @@ -123,18 +123,18 @@ void MTGGuiPlay::setCardPosition(CardGui * cardg, int player, int playerTurn, in if (!(cardg->x ==0 && cardg->y ==0)) return ; if (card->target) return; - if (spellMode && (card->isACreature() || card->hasType("land"))) return; - if (!spellMode && !card->isACreature() && !card->hasType("land")) return; - if (card->isACreature()){ + if (spellMode && (card->isCreature() || card->isLand())) return; + if (!spellMode && !card->isCreature() && !card->isLand()) return; + if (card->isCreature()){ int x_offset = nb_creatures[player] % cards_x_limit; int y_offset = nb_creatures[player] / cards_x_limit; - cardg->x= ZX_MAIN + (Z_CARDWIDTH * x_offset); - cardg->y=ZY_MAIN + ZH_CREATURES + (Z_CARDHEIGHT * y_offset) + 100 * (1-player); + cardg->x = ZX_MAIN + (Z_CARDWIDTH * x_offset); + cardg->y = ZY_MAIN + ZH_CREATURES + (Z_CARDHEIGHT * y_offset) + 100 * (1-player); nb_creatures[player]++; if (playerTurn){ if (card->isAttacker()){ - cardg->y=122 + 30 * (1-player); + cardg->y = 122 + 30 * (1-player); //Sets position of opponents as well if (player == 1){ for (list::iterator it= card->blockers.begin(); it !=card->blockers.end() ; ++it){ @@ -153,27 +153,26 @@ void MTGGuiPlay::setCardPosition(CardGui * cardg, int player, int playerTurn, in } } } - } }else{ if (card->isDefenser()){ - CardGui * targetg = getByCard(card->isDefenser()); - if (targetg) cardg->x = targetg->x; - cardg->y=122 + 30 * (1-player); + CardGui * targetg = getByCard(card->isDefenser()); + if (targetg) cardg->x = targetg->x; + cardg->y = 122 + 30 * (1-player); } } }else if(card->hasType("land")){ int x_offset = nb_lands[player] % cards_x_limit; int y_offset = nb_lands[player] / cards_x_limit; - cardg->x=ZX_MAIN + (Z_CARDWIDTH * x_offset); - cardg->y=ZY_MAIN + (Z_CARDHEIGHT * y_offset) + 200 * (1-player); + cardg->x = ZX_MAIN + (Z_CARDWIDTH * x_offset); + cardg->y = ZY_MAIN + (Z_CARDHEIGHT * y_offset) + 200 * (1-player); nb_lands[player]++; }else{ int y_offset = nb_spells[player] % Z_SPELLS_NBCARDS; int x_offset = nb_spells[player] / Z_SPELLS_NBCARDS; - cardg->x=ZX_SPELL - (Z_CARDWIDTH * x_offset); - cardg->y=ZY_SPELL + (Z_CARDHEIGHT * y_offset) + 125 * (1-player); + cardg->x = ZX_SPELL - (Z_CARDWIDTH * x_offset); + cardg->y = ZY_SPELL + (Z_CARDHEIGHT * y_offset) + 125 * (1-player); nb_spells[player]++; cards_x_limit = 12 - (nb_spells[player] + 2)/ Z_SPELLS_NBCARDS; } @@ -188,15 +187,14 @@ void MTGGuiPlay::setTargettingCardPosition(CardGui * cardg, int player, int play return; CardGui * targetg = getByCard(target); if (targetg){ - cardg->y=targetg->y + 5; - cardg->x=targetg->x + 5; + cardg->y = targetg->y + 5; + cardg->x = targetg->x + 5; } adjustCardPosition(cardg); return; } void MTGGuiPlay::forceUpdateCards(){ - GameObserver * game = GameObserver::GetInstance(); Player * player = game->players[0]; int player0Mode =(game->currentPlayer == player); int nb_cards = player->game->inPlay->nb_cards; @@ -211,14 +209,14 @@ void MTGGuiPlay::forceUpdateCards(){ for (int i = 0;igame->inPlay->cards[i],40, i*35 + 10, 200, hasFocus); + CardView* object = NEW CardView(player->game->inPlay->cards[i], i*35 + 10, 200); Add(object); hasFocus = false; } hasFocus = !player0Mode; for (int i = 0;igame->inPlay->cards[i],40, i*35 + 10, 10, hasFocus); + CardView* object = NEW CardView(opponent->game->inPlay->cards[i], i*35 + 10, 10); Add(object); hasFocus = false; } @@ -226,16 +224,17 @@ void MTGGuiPlay::forceUpdateCards(){ currentPlayer = game->currentPlayer; } -int MTGGuiPlay::receiveEvent(WEvent *event){ +int MTGGuiPlay::receiveEventPlus(WEvent *event){ WEventZoneChange * e = dynamic_cast(event); if (!e) return 0; - int ok = 0; - for (int i = 0; i < 2 ; i++){ - Player * p = game->players[i]; - if (e->from == p->game->inPlay || e->to == p->game->inPlay ) ok = 1; - } - if (!ok) return 0; - forceUpdateCards(); + if (e->from == game->players[0]->game->inPlay || e->from == game->players[1]->game->inPlay) + { + for (vector::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + if (*it == (JGuiObject*)e->card) { mObjects.erase(it); delete(*it); return 1; } + } + else if (e->to == game->players[0]->game->inPlay || e->to == game->players[1]->game->inPlay) + Add(NEW CardView(e->card, 500, 300)); + // forceUpdateCards(); updateCards(); return 1; } @@ -296,15 +295,15 @@ void MTGGuiPlay::updateCards(){ void MTGGuiPlay::AddPlayersGuiInfo(){ //init with the players objects if (mCount == 0){ - Add(NEW GuiAvatar(-1,50,2,155,false, GameObserver::GetInstance()->players[0])); - Add(NEW GuiAvatar(-2,50,2,30,false,GameObserver::GetInstance()->players[1])); + Add(NEW GuiAvatar(2,155,false, GameObserver::GetInstance()->players[0], GuiAvatar::BOTTOM_RIGHT, NULL)); + Add(NEW GuiAvatar(2,30,false,GameObserver::GetInstance()->players[1], GuiAvatar::BOTTOM_RIGHT, NULL)); - Add(NEW GuiGraveyard(-3,30,40,150,false, GameObserver::GetInstance()->players[0])); - Add(NEW GuiLibrary(-4,30,40,180,false, GameObserver::GetInstance()->players[0])); + Add(NEW GuiGraveyard(40,150,false, GameObserver::GetInstance()->players[0], NULL)); + Add(NEW GuiLibrary(40,180,false, GameObserver::GetInstance()->players[0], NULL)); - Add(NEW GuiGraveyard(-5,30,40,30,false, GameObserver::GetInstance()->players[1])); - Add(NEW GuiLibrary(-6,30,40,60,false, GameObserver::GetInstance()->players[1])); + Add(NEW GuiGraveyard(40,30,false, GameObserver::GetInstance()->players[1], NULL)); + Add(NEW GuiLibrary(40,60,false, GameObserver::GetInstance()->players[1], NULL)); } } @@ -322,7 +321,7 @@ bool MTGGuiPlay::CheckUserInput(u32 key){ return zone->cd->CheckUserInput(key); } } - return PlayGuiObjectController::CheckUserInput(key); + return true; //PlayGuiObjectController::CheckUserInput(key); } @@ -439,7 +438,7 @@ void MTGGuiPlay::Render(){ if (hasFocus && mCurr >= offset && showBigCards && !game->currentlyActing()->isAI() ){ //For some reason RenderBig crashes when the testsuite is playing, so we add a "isAI()" test...which was supposed to be there at some point anyways... CardGui * cardg = ((CardGui *)mObjects[mCurr]); - cardg->RenderBig(-1,-1,showBigCards-1); + //cardg->RenderBig(-1,-1,showBigCards-1); } } LOG("End MTGGuiPlay Render\n"); diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index b02745636..7ab6ac5ed 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -53,7 +53,7 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card){ card->getManaCost()->doPayExtra(); ManaCost * spellCost = previousManaPool->Diff(player->getManaPool()); delete previousManaPool; - if (card->hasType("land")){ + if (card->hasType("land")){ MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->stack); Spell * spell = NEW Spell(copy); spell->resolve(); @@ -65,9 +65,8 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card){ if (game->targetChooser){ spell = game->mLayers->stackLayer()->addSpell(card,game->targetChooser, spellCost); game->targetChooser = NULL; - }else{ + }else spell = game->mLayers->stackLayer()->addSpell(card,NULL, spellCost); - } MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->stack); spell->source = copy; } @@ -85,10 +84,10 @@ ostream& MTGPutInPlayRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } - MTGPutInPlayRule * MTGPutInPlayRule::clone() const{ - MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this); - a->isClone = 1; - return a; + MTGPutInPlayRule * MTGPutInPlayRule::clone() const{ + MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this); + a->isClone = 1; + return a; } @@ -132,10 +131,10 @@ ostream& MTGAttackRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } - MTGAttackRule * MTGAttackRule::clone() const{ - MTGAttackRule * a = NEW MTGAttackRule(*this); - a->isClone = 1; - return a; + MTGAttackRule * MTGAttackRule::clone() const{ + MTGAttackRule * a = NEW MTGAttackRule(*this); + a->isClone = 1; + return a; } @@ -160,10 +159,10 @@ int MTGBlockRule::reactToClick(MTGCardInstance * card){ currentOpponent = game->currentPlayer->game->inPlay->getNextAttacker(currentOpponent); #if defined (WIN32) || defined (LINUX) char buf[4096]; - sprintf(buf,"Defenser Toggle %s \n" ,card->model->getName()); + sprintf(buf,"Defenser Toggle %s \n", card->model->getName().c_str()); OutputDebugString(buf); #endif - candefend = card->toggleDefenser(currentOpponent); + candefend = card->toggleDefenser(currentOpponent); result = (candefend || currentOpponent == NULL); } return 1; @@ -180,10 +179,10 @@ ostream& MTGBlockRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } - MTGBlockRule * MTGBlockRule::clone() const{ - MTGBlockRule * a = NEW MTGBlockRule(*this); - a->isClone = 1; - return a; + MTGBlockRule * MTGBlockRule::clone() const{ + MTGBlockRule * a = NEW MTGBlockRule(*this); + a->isClone = 1; + return a; } // // Attacker chooses blockers order @@ -201,7 +200,7 @@ MTGMomirRule::MTGMomirRule(int _id, MTGAllCards * _collection):MTGAbility(_id, N if (!initialized){ for (size_t i = 0; i < collection->ids.size(); i++){ MTGCard * card = collection->collection[collection->ids[i]]; - if (card->isACreature()){ + if (card->isCreature()){ int convertedCost = card->getManaCost()->getConvertedCost(); if (convertedCost>20) continue; pool[convertedCost].push_back(card->getMTGId()); @@ -239,7 +238,7 @@ int MTGMomirRule::reactToClick(MTGCardInstance * card_to_discard){ int MTGMomirRule::reactToClick(MTGCardInstance * card_to_discard, int cardId){ if (!isReactingToClick(card_to_discard)) return 0; Player * player = game->currentlyActing(); - ManaCost * cost = player->getManaPool(); + ManaCost * cost = player->getManaPool(); player->getManaPool()->pay(cost); MTGCardInstance * card = genCreature(cardId); player->game->putInZone(card_to_discard, player->game->hand, player->game->graveyard); @@ -312,10 +311,10 @@ ostream& MTGMomirRule::toString(ostream& out) const } - MTGMomirRule * MTGMomirRule::clone() const{ - MTGMomirRule * a = NEW MTGMomirRule(*this); - a->isClone = 1; - return a; + MTGMomirRule * MTGMomirRule::clone() const{ + MTGMomirRule * a = NEW MTGMomirRule(*this); + a->isClone = 1; + return a; } //HUDDisplay @@ -329,7 +328,7 @@ void HUDDisplay::Update(float dt){ if (events.size()){ list::iterator it = events.begin(); HUDString * hs = *it; - if (popdelay > 1 && timestamp - hs->timestamp > 2){ + if (popdelay > 1 && timestamp - hs->timestamp > 2){ events.pop_front(); delete hs; if (events.size()) popdelay = 0; @@ -372,7 +371,7 @@ int HUDDisplay::receiveEvent(WEvent * event){ return 0; } void HUDDisplay::Render(){ - if (!GameOptions::GetInstance()->values[OPTIONS_OSD].getIntValue()) return; + if (!options[Options::OSD].number) return; if (!events.size()) return; f->SetColor(ARGB(255,255,255,255)); @@ -398,7 +397,7 @@ HUDDisplay::HUDDisplay(int _id):MTGAbility(_id, NULL){ f = GameApp::CommonRes->GetJLBFont(Constants::MAIN_FONT); maxWidth = 0; } - + HUDDisplay::~HUDDisplay(){ list::iterator it; for (it = events.begin(); it !=events.end(); ++it){ @@ -408,14 +407,14 @@ HUDDisplay::~HUDDisplay(){ events.clear(); } - HUDDisplay * HUDDisplay::clone() const{ - HUDDisplay * a = NEW HUDDisplay(*this); - a->isClone = 1; - return a; - } - - - /* Persist */ + HUDDisplay * HUDDisplay::clone() const{ + HUDDisplay * a = NEW HUDDisplay(*this); + a->isClone = 1; + return a; + } + + + /* Persist */ MTGPersistRule::MTGPersistRule(int _id):MTGAbility(_id,NULL){}; int MTGPersistRule::receiveEvent(WEvent * event){ @@ -452,8 +451,8 @@ HUDDisplay::~HUDDisplay(){ } int MTGPersistRule::testDestroy(){return 0;} MTGPersistRule * MTGPersistRule::clone() const{ - MTGPersistRule * a = NEW MTGPersistRule(*this); - a->isClone = 1; + MTGPersistRule * a = NEW MTGPersistRule(*this); + a->isClone = 1; return a; } @@ -473,7 +472,7 @@ HUDDisplay::~HUDDisplay(){ int destroy = 0; for ( it=cards.begin() ; it != cards.end(); it++ ){ MTGCardInstance * comparison = (*it).first; - if (comparison!= card && !strcmp(comparison->getName(), card->getName())){ + if (comparison != card && !(comparison->getName().compare(card->getName()))){ comparison->owner->game->putInGraveyard(comparison); destroy = 1; } @@ -493,8 +492,8 @@ HUDDisplay::~HUDDisplay(){ return out << "MTGLegendRule :::"; } MTGLegendRule * MTGLegendRule::clone() const{ - MTGLegendRule * a = NEW MTGLegendRule(*this); - a->isClone = 1; + MTGLegendRule * a = NEW MTGLegendRule(*this); + a->isClone = 1; return a; } @@ -522,7 +521,7 @@ HUDDisplay::~HUDDisplay(){ return MTGAbility::toString(out) << ")"; } MTGLifelinkRule * MTGLifelinkRule::clone() const{ - MTGLifelinkRule * a = NEW MTGLifelinkRule(*this); - a->isClone = 1; + MTGLifelinkRule * a = NEW MTGLifelinkRule(*this); + a->isClone = 1; return a; - } \ No newline at end of file + } diff --git a/projects/mtg/src/OptionItem.cpp b/projects/mtg/src/OptionItem.cpp index 849e77b0e..bd0a85ed6 100644 --- a/projects/mtg/src/OptionItem.cpp +++ b/projects/mtg/src/OptionItem.cpp @@ -9,14 +9,14 @@ OptionItem::OptionItem(string _id, string _displayValue, int _maxValue, int _inc maxValue = _maxValue; increment = _increment; displayValue = _(_displayValue); - value = GameOptions::GetInstance()->values[id].getIntValue(); + value = options[id].number; hasFocus = 0; x = 0; y = 0; } void OptionItem::setData(){ - GameOptions::GetInstance()->values[id] = GameOption(value); + options[id] = GameOption(value); } void OptionItem::Render(){ @@ -60,8 +60,6 @@ bool OptionItem::Leaving(){ } -OptionItem * options[20]; -int nbitems; OptionsList::OptionsList(){ nbitems = 0; current = -1; @@ -100,7 +98,7 @@ void OptionsList::save(){ for (int i = 0; i < nbitems; i++){ options[i]->setData(); } - GameOptions::GetInstance()->save(); + ::options.save(); } void OptionsList::Update(float dt){ diff --git a/projects/mtg/src/PlayGuiObject.cpp b/projects/mtg/src/PlayGuiObject.cpp index 6e488965f..070d07242 100644 --- a/projects/mtg/src/PlayGuiObject.cpp +++ b/projects/mtg/src/PlayGuiObject.cpp @@ -1,15 +1,19 @@ +#include #include "../include/config.h" #include "../include/PlayGuiObject.h" -#include "../include/Player.h" -#include "../include/MTGGameZones.h" -#include "../include/CardDisplay.h" +using namespace std; -PlayGuiObject::PlayGuiObject(int id, float desiredHeight,float _x, float _y, bool hasFocus): JGuiObject(id){ +PlayGuiObject::PlayGuiObject(float desiredHeight, float x, float y, bool hasFocus) : JGuiObject(0), Pos(x, y, 1.0, 0.0, 255) { + defaultHeight = desiredHeight; + mHeight = desiredHeight; + mHasFocus = hasFocus; + type = 0; + wave = 0; +} +PlayGuiObject::PlayGuiObject(float desiredHeight, const Pos& ref, bool hasFocus) : JGuiObject(0), Pos(ref) { defaultHeight = desiredHeight; mHeight = desiredHeight; - x = _x; - y = _y; mHasFocus = hasFocus; type = 0; wave = 0; @@ -32,143 +36,13 @@ void PlayGuiObject::Update(float dt){ mHeight = defaultHeight; } wave = (wave +2) % 255; + for (vector::iterator it = effects.begin(); it != effects.end(); ++it) + (*it)->Update(dt); + Pos::Update(dt); } -GuiAvatar::GuiAvatar(int id, float desiredHeight,float _x, float _y, bool hasFocus, Player * _player): PlayGuiObject(id, desiredHeight, _x, _y, hasFocus){ - player= _player; - avatarRed = 255; - currentLife = player->life; - type = GUI_AVATAR; -} - -void GuiAvatar::Render(){ - GameObserver * game = GameObserver::GetInstance(); - JRenderer * r = JRenderer::GetInstance(); - int life = player->life; - JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MAIN_FONT); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - //Avatar - int lifeDiff = life - currentLife; - if (lifeDiff < 0 && currentLife >0 ){ - avatarRed = 192 + (3* 255 * lifeDiff)/ currentLife / 4; - if (avatarRed<0) - avatarRed = 0; - } - currentLife= life; - - JQuad * quad = player->mAvatar; - if(quad){ - quad->SetColor(ARGB(255,255,avatarRed,avatarRed)); - r->RenderQuad(quad,x,y); - if (mHasFocus){ - r->FillRect(x,y,quad->mWidth,quad->mHeight,ARGB(abs(wave-128), 255,255,255)); - } - } - - if (avatarRed < 255){ - avatarRed+=3; - if (avatarRed >255) - avatarRed = 255; - } - if(game->currentPlayer == player){ - r->DrawRect(x-1,y-1 ,37,52,ARGB(255,0,255,0)); - }else if (game->currentActionPlayer == player){ - r->DrawRect(x,y,35,50,ARGB(255,0,0,255)); - } - if(game->isInterrupting == player){ - r->DrawRect(x,y ,35,50,ARGB(255,255,0,0)); - } - - //Life - char buffer[5]; - sprintf(buffer, "%i",life); - mFont->SetColor(ARGB(128,0,0,0)); - mFont->DrawString(buffer, x+3,y+40); - mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(buffer, x+1,y+38); -} - -ostream& GuiAvatar::toString(ostream& out) const +void PlayGuiObject::Render() { - return out << "GuiAvatar ::: avatarRed : " << avatarRed - << " ; currentLife : " << currentLife - << " ; player : " << player; -} - - -void GuiGameZone::toggleDisplay(){ - if (showCards){ - showCards = 0; - }else{ - showCards = 1; - cd->init(zone); - } -} - - -void GuiGameZone::Render(){ - //Texture - JQuad * quad = GameApp::CommonRes->GetQuad("back_thumb"); - float scale = defaultHeight / quad->mHeight; - quad->SetColor(ARGB(255,255,255,255)); - - JRenderer::GetInstance()->RenderQuad(quad,x,y,0.0,scale, scale); - if (mHasFocus){ - JRenderer::GetInstance()->FillRect(x,y,quad->mWidth*scale,quad->mHeight*scale,ARGB(abs(wave-128), 255,255,255)); - } - //Number of cards - JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MAIN_FONT); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - char buffer[512]; - sprintf(buffer,"%i", zone->nb_cards); - mFont->SetColor(ARGB(128,0,0,0)); - mFont->DrawString(buffer, x+2, y+2); - mFont->SetColor(ARGB(255,255,255,255)); - mFont->DrawString(buffer, x, y); - - if (showCards) cd->Render(); -} - -void GuiGameZone::ButtonPressed(int controllerId, int controlId){ - GameObserver::GetInstance()->ButtonPressed(GetId(), this); -} - -void GuiGameZone::Update(float dt){ - if (showCards) cd->Update(dt); - PlayGuiObject::Update(dt); -} - -GuiGameZone::GuiGameZone(int id, float desiredHeight,float _x, float _y, bool hasFocus,MTGGameZone * _zone): PlayGuiObject(id, desiredHeight, _x, _y, hasFocus), zone(_zone){ - cd = NEW CardDisplay(id, GameObserver::GetInstance(), _x, _y,this); - showCards = 0; -} - -GuiGameZone::~GuiGameZone(){ - if(cd) delete cd; -} - -ostream& GuiGameZone::toString(ostream& out) const -{ - return out << "GuiGameZone ::: zone : " << zone - << " ; cd : " << cd - << " ; showCards : " << showCards; -} - -GuiGraveyard::GuiGraveyard(int id, float desiredHeight,float _x, float _y, bool hasFocus,Player * player):GuiGameZone(id, desiredHeight, _x, _y, hasFocus,player->game->graveyard){ - type= GUI_GRAVEYARD; -} - -ostream& GuiGraveyard::toString(ostream& out) const -{ - return out << "GuiGraveyard :::"; -} - -GuiLibrary::GuiLibrary(int id, float desiredHeight,float _x, float _y, bool hasFocus,Player * player):GuiGameZone(id, desiredHeight, _x, _y, hasFocus,player->game->library){ - type = GUI_LIBRARY; -} - - -ostream& GuiLibrary::toString(ostream& out) const -{ - return out << "GuiLibrary :::"; + for (vector::iterator it = effects.begin(); it != effects.end(); ++it) + (*it)->Render(); } diff --git a/projects/mtg/src/PlayGuiObjectController.cpp b/projects/mtg/src/PlayGuiObjectController.cpp index 16d36d870..4492dd89b 100644 --- a/projects/mtg/src/PlayGuiObjectController.cpp +++ b/projects/mtg/src/PlayGuiObjectController.cpp @@ -86,6 +86,7 @@ void PlayGuiObjectController::Update(float dt){ bool PlayGuiObjectController::CheckUserInput(u32 key){ + /* if (!mCount) return false; if (game != NULL){ @@ -148,5 +149,6 @@ bool PlayGuiObjectController::CheckUserInput(u32 key){ showBigCards = (showBigCards + 1) % 3; return true; } + */ return false; } diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index cb4f71efe..164a24050 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -4,10 +4,10 @@ #include "../include/DeckStats.h" -Player::Player(MTGPlayerCards * _deck, string file, string fileSmall): Damageable(20){ +Player::Player(MTGPlayerCards * deck, string file, string fileSmall) : Damageable(20){ deckFile = file; deckFileSmall = fileSmall; - game = _deck; + game = deck; game->setOwner(this); manaPool = NEW ManaCost(); canPutLandsIntoPlay = 1; @@ -26,7 +26,7 @@ Player::~Player(){ if (mAvatar) delete mAvatar; } -const char * Player::getDisplayName(){ +const string Player::getDisplayName(){ GameObserver * g = GameObserver::GetInstance(); if (this == g->players[0]) return "Player 1"; return "Player 2"; @@ -57,7 +57,7 @@ Player * Player::opponent(){ return NULL; } -HumanPlayer::HumanPlayer(MTGPlayerCards * _deck, char * file, string fileSmall):Player(_deck, file, fileSmall){ +HumanPlayer::HumanPlayer(MTGPlayerCards * deck, string file, string fileSmall) : Player(deck, file, fileSmall) { mAvatarTex = JRenderer::GetInstance()->LoadTexture("player/avatar.jpg", TEX_TYPE_USE_VRAM); if (mAvatarTex) mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); diff --git a/projects/mtg/src/ReplacementEffects.cpp b/projects/mtg/src/ReplacementEffects.cpp index 513e70464..4c03773e7 100644 --- a/projects/mtg/src/ReplacementEffects.cpp +++ b/projects/mtg/src/ReplacementEffects.cpp @@ -1,76 +1,76 @@ -#include "../include/config.h" -#include "../include/ReplacementEffects.h" -#include "../include/MTGCardInstance.h" -#include "../include/TargetChooser.h" -#include "../include/Damage.h" - - -REDamagePrevention::REDamagePrevention(MTGAbility * _source, TargetChooser *_tcSource, TargetChooser *_tcTarget,int _damage, bool _oneShot):source(_source),tcSource(_tcSource), tcTarget(_tcTarget),damage(_damage), oneShot(_oneShot){ -} - -WEvent * REDamagePrevention::replace (WEvent *event){ - if (!event) return event; - if (!damage) return event; - WEventDamage * e = dynamic_cast(event); - if (!e) return event; - Damage *d = e->damage; - if ((!tcSource || tcSource->canTarget(d->source)) && - (!tcTarget || tcTarget->canTarget(d->target)) - ){ - if (damage == -1){ - d->damage = 0; - delete event; - if (oneShot) damage = 0; - return NULL; - } - if (damage >= d->damage){ - damage-= d->damage; - d->damage = 0; - delete event; - return NULL; - } - d->damage -= damage; - damage = 0; - delete event; - WEventDamage* newEvent = NEW WEventDamage(d); - return newEvent; - } - return event; -} -REDamagePrevention::~REDamagePrevention(){ - SAFE_DELETE(tcSource); - SAFE_DELETE(tcTarget); -} - -ReplacementEffects::ReplacementEffects(){} - -WEvent * ReplacementEffects::replace(WEvent *e){ - list::iterator it; - - for ( it=modifiers.begin() ; it != modifiers.end(); it++ ){ - ReplacementEffect *re = *it; - WEvent * newEvent = re->replace(e); - if (!newEvent) return NULL; - if (newEvent != e) return replace(newEvent); - } - return e; -} - -int ReplacementEffects::add(ReplacementEffect * re){ - modifiers.push_back(re); - return 1; -} - -int ReplacementEffects::remove (ReplacementEffect *re){ - modifiers.remove(re); - return 1; -} - -ReplacementEffects::~ReplacementEffects(){ - list::iterator it; - for ( it=modifiers.begin() ; it != modifiers.end(); it++ ){ - ReplacementEffect *re = *it; - delete(re); - } - modifiers.clear(); -} \ No newline at end of file +#include "../include/config.h" +#include "../include/ReplacementEffects.h" +#include "../include/MTGCardInstance.h" +#include "../include/TargetChooser.h" +#include "../include/Damage.h" + + +REDamagePrevention::REDamagePrevention(MTGAbility * source, TargetChooser *tcSource, TargetChooser *tcTarget, int damage, bool oneShot):source(source), tcSource(tcSource), tcTarget(tcTarget), damage(damage), oneShot(oneShot){ +} + +WEvent * REDamagePrevention::replace (WEvent *event){ + if (!event) return event; + if (!damage) return event; + WEventDamage * e = dynamic_cast(event); + if (!e) return event; + Damage *d = e->damage; + if ((!tcSource || tcSource->canTarget(d->source)) && + (!tcTarget || tcTarget->canTarget(d->target)) + ){ + if (damage == -1){ + d->damage = 0; + delete event; + if (oneShot) damage = 0; + return NULL; + } + if (damage >= d->damage){ + damage-= d->damage; + d->damage = 0; + delete event; + return NULL; + } + d->damage -= damage; + damage = 0; + delete event; + WEventDamage* newEvent = NEW WEventDamage(d); + return newEvent; + } + return event; +} +REDamagePrevention::~REDamagePrevention(){ + SAFE_DELETE(tcSource); + SAFE_DELETE(tcTarget); +} + +ReplacementEffects::ReplacementEffects(){} + +WEvent * ReplacementEffects::replace(WEvent *e){ + list::iterator it; + + for ( it=modifiers.begin() ; it != modifiers.end(); it++ ){ + ReplacementEffect *re = *it; + WEvent * newEvent = re->replace(e); + if (!newEvent) return NULL; + if (newEvent != e) return replace(newEvent); + } + return e; +} + +int ReplacementEffects::add(ReplacementEffect * re){ + modifiers.push_back(re); + return 1; +} + +int ReplacementEffects::remove (ReplacementEffect *re){ + modifiers.remove(re); + return 1; +} + +ReplacementEffects::~ReplacementEffects(){ + list::iterator it; + for ( it=modifiers.begin() ; it != modifiers.end(); it++ ){ + ReplacementEffect *re = *it; + delete(re); + } + modifiers.clear(); +} diff --git a/projects/mtg/src/ShopItem.cpp b/projects/mtg/src/ShopItem.cpp index ba110e91c..071246bca 100644 --- a/projects/mtg/src/ShopItem.cpp +++ b/projects/mtg/src/ShopItem.cpp @@ -2,21 +2,21 @@ #include "../include/ShopItem.h" #include "../include/GameStateShop.h" #include "../include/CardGui.h" +#include "../include/TexturesCache.h" #include "../include/Translate.h" #include + float ShopItems::_x1[] = { 40, 3, 23, 99,142,182, 90,132,177,106,163}; + float ShopItems::_y1[] = {156,174,194,166,166,162,184,185,180,211,208}; - float ShopItems::_x1[] = { 40, 3, 23, 99,142,182, 90,132,177,106,163}; - float ShopItems::_y1[] = {156,174,194,166,166,162,184,185,180,211,208}; - - float ShopItems::_x2[] = { 44, 25, 64,128,171,211,121,165,209,143,200}; - float ShopItems::_y2[] = {147,163,190,166,166,162,184,185,180,211,208}; - - float ShopItems::_x3[] = { 86, 47, 12, 85,133,177, 73,120,170, 88,153}; - float ShopItems::_y3[] = {152,177,216,181,180,176,203,204,198,237,232}; - - float ShopItems::_x4[] = { 86, 66, 58,118,164,207,108,156,205,130,199}; + float ShopItems::_x2[] = { 44, 25, 64,128,171,211,121,165,209,143,200}; + float ShopItems::_y2[] = {147,163,190,166,166,162,184,185,180,211,208}; + + float ShopItems::_x3[] = { 86, 47, 12, 85,133,177, 73,120,170, 88,153}; + float ShopItems::_y3[] = {152,177,216,181,180,176,203,204,198,237,232}; + + float ShopItems::_x4[] = { 86, 66, 58,118,164,207,108,156,205,130,199}; float ShopItems::_y4[] = {145,167,211,181,180,176,203,204,198,237,232}; ShopItem::ShopItem(int id, JLBFont *font, char* text, JQuad * _quad,JQuad * _thumb, float _xy[], bool hasFocus, int _price): JGuiObject(id), mFont(font), mText(text), quad(_quad), thumb(_thumb), price(_price) @@ -31,16 +31,16 @@ ShopItem::ShopItem(int id, JLBFont *font, char* text, JQuad * _quad,JQuad * _thu mScale = 1.0f; mTargetScale = 1.0f; - mesh=NEW hgeDistortionMesh(2,2); - mesh->SetTexture(thumb->mTex); - float x0,y0,w0,h0; - thumb->GetTextureRect(&x0,&y0,&w0,&h0); - mesh->SetTextureRect(x0,y0,w0,h0); - mesh->Clear(ARGB(0xFF,0xFF,0xFF,0xFF)); - mesh->SetDisplacement(0, 0, xy[0],xy[1], HGEDISP_NODE); - mesh->SetDisplacement(1, 0, xy[2] - w0,xy[3], HGEDISP_NODE); - mesh->SetDisplacement(0, 1,xy[4],xy[5]-h0, HGEDISP_NODE); - mesh->SetDisplacement(1, 1, xy[6]-w0,xy[7]-h0, HGEDISP_NODE); + mesh=NEW hgeDistortionMesh(2,2); + mesh->SetTexture(thumb->mTex); + float x0,y0,w0,h0; + thumb->GetTextureRect(&x0,&y0,&w0,&h0); + mesh->SetTextureRect(x0,y0,w0,h0); + mesh->Clear(ARGB(0xFF,0xFF,0xFF,0xFF)); + mesh->SetDisplacement(0, 0, xy[0],xy[1], HGEDISP_NODE); + mesh->SetDisplacement(1, 0, xy[2] - w0,xy[3], HGEDISP_NODE); + mesh->SetDisplacement(0, 1,xy[4],xy[5]-h0, HGEDISP_NODE); + mesh->SetDisplacement(1, 1, xy[6]-w0,xy[7]-h0, HGEDISP_NODE); mesh->SetColor(1,1,ARGB(255,100,100,100)); mesh->SetColor(0,1,ARGB(255,100,100,100)); mesh->SetColor(1,0,ARGB(255,100,100,100)); @@ -66,19 +66,20 @@ ShopItem::ShopItem(int id, JLBFont *font, int _cardid, float _xy[], bool hasFocu quantity = 1 + (rand() % 4); if (card->getRarity() == Constants::RARITY_L) quantity = 50; quad = NULL; - thumb = card->getThumb(); - if (!thumb) thumb = GameApp::CommonRes->GetQuad("back_thumb"); + // thumb = card->getThumb(); + // if (!thumb) + thumb = GameApp::CommonRes->GetQuad("back_thumb"); if (thumb){ - mesh=NEW hgeDistortionMesh(2,2); - mesh->SetTexture(thumb->mTex); - float x0,y0,w0,h0; - thumb->GetTextureRect(&x0,&y0,&w0,&h0); - mesh->SetTextureRect(x0,y0,w0,h0); - mesh->Clear(ARGB(0xFF,0xFF,0xFF,0xFF)); - mesh->SetDisplacement(0, 0, xy[0],xy[1], HGEDISP_NODE); - mesh->SetDisplacement(1, 0, xy[2] - w0,xy[3], HGEDISP_NODE); - mesh->SetDisplacement(0, 1,xy[4],xy[5]-h0, HGEDISP_NODE); - mesh->SetDisplacement(1, 1, xy[6]-w0,xy[7]-h0, HGEDISP_NODE); + mesh=NEW hgeDistortionMesh(2,2); + mesh->SetTexture(thumb->mTex); + float x0,y0,w0,h0; + thumb->GetTextureRect(&x0,&y0,&w0,&h0); + mesh->SetTextureRect(x0,y0,w0,h0); + mesh->Clear(ARGB(0xFF,0xFF,0xFF,0xFF)); + mesh->SetDisplacement(0, 0, xy[0],xy[1], HGEDISP_NODE); + mesh->SetDisplacement(1, 0, xy[2] - w0,xy[3], HGEDISP_NODE); + mesh->SetDisplacement(0, 1,xy[4],xy[5]-h0, HGEDISP_NODE); + mesh->SetDisplacement(1, 1, xy[6]-w0,xy[7]-h0, HGEDISP_NODE); mesh->SetColor(1,1,ARGB(255,100,100,100)); mesh->SetColor(0,1,ARGB(255,100,100,100)); mesh->SetColor(1,0,ARGB(255,100,100,100)); @@ -114,9 +115,8 @@ void ShopItem::Render(){ if (!quantity){ mFont->SetColor(ARGB(255,128,128,128)); } - - - if (card){ + + if (card){ if (nameCount){ char buffer[512]; sprintf(buffer, "%s (%i)", _(card->name).c_str(), nameCount ); @@ -136,7 +136,7 @@ void ShopItem::Render(){ renderer->FillPolygon(xs,ys,4,ARGB(200,0,0,0)); x0 = mX + 230 -30; mFont->DrawString(mText.c_str(), x0, mY + 8,JGETEXT_RIGHT); - + }else{ float xs[] = {mX-5, mX-5, mX-5+230,mX-5+230,}; float ys[] = {mY-5,mY-5+35,mY-5+17,mY-5+19} ; @@ -153,14 +153,12 @@ void ShopItem::Render(){ //NOTHING } if (mHasFocus){ - if (card){ - quad = card->getQuad(); - } + if (card) quad = cache.getQuad(card); if (quad){ quad->SetColor(ARGB(255,255,255,255)); renderer->RenderQuad(quad,SCREEN_WIDTH/2 + 50,5,0, 0.9f,0.9f); }else{ - if (card) CardGui::alternateRender(card,NULL,SCREEN_WIDTH/2 + 100 + 20,133,0, 0.9f); + // if (card) CardGui::alternateRender(card,NULL,SCREEN_WIDTH/2 + 100 + 20,133,0, 0.9f); } mFont->DrawString(mText.c_str(), 100, SCREEN_HEIGHT - 30); } @@ -336,7 +334,7 @@ void ShopItems::ButtonPressed(int controllerId, int controlId){ tempDeck->addRandomCards(1, sets,1,rare_or_mythic); tempDeck->addRandomCards(3, sets,1,Constants::RARITY_U); tempDeck->addRandomCards(11, sets,1,Constants::RARITY_C); - + playerdata->collection->add(tempDeck); myCollection->Add(tempDeck); @@ -344,7 +342,7 @@ void ShopItems::ButtonPressed(int controllerId, int controlId){ ShopItem * si = ((ShopItem *)mObjects[j]); si->updateCount(myCollection); } - + int i = 0; for (map::iterator it = tempDeck->cards.begin(); it!=tempDeck->cards.end(); it++){ MTGCard * c = tempDeck->getCardById(it->first); diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index 87f970396..4a3711b5b 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -41,7 +41,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta s2 = ""; } zones[nbzones] = MTGGameZone::MY_BATTLEFIELD; - + //Graveyards if(zoneName.compare("graveyard") == 0){ zones[nbzones] = MTGGameZone::MY_GRAVEYARD; @@ -274,16 +274,16 @@ TargetChooser::TargetChooser(MTGCardInstance * card, int _maxtargets): TargetsLi //Default targetter : every card can be targetted, unless it is protected from the targetter card // For spells that do not "target" a specific card, set targetter to NULL -int TargetChooser::canTarget(Targetable * target){ +bool TargetChooser::canTarget(Targetable * target){ if (target->typeAsTarget() == TARGET_CARD){ MTGCardInstance * card = (MTGCardInstance *) target; - if (targetter && card->isInPlay() && (card->has(Constants::SHROUD)|| card->protectedAgainst(targetter) )) return 0; - if (source && targetter && card->isInPlay() && (source->controller() != card->controller()) && (card->has(Constants::OPPONENTSHROUD)|| card->protectedAgainst(targetter) )) return 0; - return 1; - }else if (target->typeAsTarget() == TARGET_STACKACTION){ - return 1; + if (source && card->isInPlay() && (card->has(Constants::SHROUD)|| card->protectedAgainst(source) )) return false; + if (source && targetter && card->isInPlay() && (source->controller() != card->controller()) && (card->has(Constants::OPPONENTSHROUD) || card->protectedAgainst(targetter))) return false; + return true; } - return 0; + else if (target->typeAsTarget() == TARGET_STACKACTION) + return true; + return false; } @@ -340,17 +340,17 @@ CardTargetChooser::CardTargetChooser(MTGCardInstance * _card, MTGCardInstance * validTarget = _card; } -int CardTargetChooser::canTarget(Targetable * target ){ - if (!target) return 0; - if (target->typeAsTarget() != TARGET_CARD) return 0; - if (!nbzones && !TargetChooser::canTarget(target)) return 0; - if (nbzones && !TargetZoneChooser::canTarget(target)) return 0; +bool CardTargetChooser::canTarget(Targetable * target ){ + if (!target) return false; + if (target->typeAsTarget() != TARGET_CARD) return false; + if (!nbzones && !TargetChooser::canTarget(target)) return false; + if (nbzones && !TargetZoneChooser::canTarget(target)) return false; MTGCardInstance * card = (MTGCardInstance *) target; - while(card){ - if(card == validTarget) return 1; + while (card) { + if (card == validTarget) return true; card = card->previous; } - return 0; + return false; } /** @@ -386,28 +386,28 @@ void TypeTargetChooser::addType(int type){ nbtypes++; } -int TypeTargetChooser::canTarget(Targetable * target ){ - if (!TargetZoneChooser::canTarget(target)) return 0; +bool TypeTargetChooser::canTarget(Targetable * target){ + if (!TargetZoneChooser::canTarget(target)) return false; if (target->typeAsTarget() == TARGET_CARD){ MTGCardInstance * card = (MTGCardInstance *) target; for (int i= 0; i < nbtypes; i++){ - if (card->hasSubtype(types[i])) return 1; - if (Subtypes::subtypesList->find(card->name) == types[i]) return 1; + if (card->hasSubtype(types[i])) return true; + if (Subtypes::subtypesList->find(card->name) == types[i]) return true; } - return 0; + return false; }else if (target->typeAsTarget() == TARGET_STACKACTION){ Interruptible * action = (Interruptible *) target; if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){ Spell * spell = (Spell *) action; MTGCardInstance * card = spell->source; for (int i= 0; i < nbtypes; i++){ - if (card->hasSubtype(types[i])) return 1; - if (Subtypes::subtypesList->find(card->name) == types[i]) return 1; + if (card->hasSubtype(types[i])) return true; + if (Subtypes::subtypesList->find(card->name) == types[i]) return true; } - return 0; + return false; } } - return 0; + return false; } @@ -430,20 +430,20 @@ DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, int * _zo cd = _cd; } -int DescriptorTargetChooser::canTarget(Targetable * target){ - if (!TargetZoneChooser::canTarget(target)) return 0; +bool DescriptorTargetChooser::canTarget(Targetable * target){ + if (!TargetZoneChooser::canTarget(target)) return false; if (target->typeAsTarget() == TARGET_CARD){ MTGCardInstance * _target = (MTGCardInstance *) target; - if (cd->match(_target)) return 1; + if (cd->match(_target)) return true; }else if (target->typeAsTarget() == TARGET_STACKACTION){ Interruptible * action = (Interruptible *) target; if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){ Spell * spell = (Spell *) action; MTGCardInstance * card = spell->source; - if (cd->match(card)) return 1; + if (cd->match(card)) return true; } } - return 0; + return false; } DescriptorTargetChooser::~DescriptorTargetChooser(){ @@ -473,15 +473,15 @@ CreatureTargetChooser::CreatureTargetChooser(int * _zones, int nbzones, MTGCardI } -int CreatureTargetChooser::canTarget(Targetable * target){ - if (!TargetZoneChooser::canTarget(target)) return 0; +bool CreatureTargetChooser::canTarget(Targetable * target){ + if (!TargetZoneChooser::canTarget(target)) return false; if (target->typeAsTarget() == TARGET_CARD){ MTGCardInstance * card = (MTGCardInstance *) target; - if (maxpower != -1 && card->power > maxpower) return 0; - if (maxtoughness != -1 && card->toughness > maxtoughness) return 0; - return card->isACreature(); + if (maxpower != -1 && card->power > maxpower) return false; + if (maxtoughness != -1 && card->toughness > maxtoughness) return false; + return card->isCreature(); } - return 0; + return false; } @@ -502,57 +502,47 @@ int TargetZoneChooser::init(int * _zones, int _nbzones){ return nbzones; } -int TargetZoneChooser::canTarget(Targetable * target){ - if (!TargetChooser::canTarget(target)) return 0; +bool TargetZoneChooser::canTarget(Targetable * target){ + if (!TargetChooser::canTarget(target)) return false; if (target->typeAsTarget() == TARGET_CARD){ MTGCardInstance * card = (MTGCardInstance *) target; - for (int i = 0; ihasCard(card)) return 1; - } + for (int i = 0; ihasCard(card)) return true; }else if (target->typeAsTarget() == TARGET_STACKACTION){ OutputDebugString ("CHECKING INTERRUPTIBLE\n"); Interruptible * action = (Interruptible *) target; if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){ Spell * spell = (Spell *) action; MTGCardInstance * card = spell->source; - for (int i = 0; ihasCard(card)) return 1; - } + for (int i = 0; ihasCard(card)) return true; } } - return 0; + return false; } int TargetZoneChooser::targetsZone(MTGGameZone * z){ - for (int i = 0; i < nbzones; i++){ + for (int i = 0; i < nbzones; i++) if (MTGGameZone::intToZone(zones[i],source) == z) return 1; - - } return 0; } /* Player Target */ - -PlayerTargetChooser::PlayerTargetChooser(MTGCardInstance * card, int _maxtargets, Player *_p):TargetChooser(card, _maxtargets){ - p = _p; +PlayerTargetChooser::PlayerTargetChooser(MTGCardInstance * card, int _maxtargets, Player *p):TargetChooser(card, _maxtargets), p(p){ } -int PlayerTargetChooser::canTarget(Targetable * target){ - if (target->typeAsTarget() == TARGET_PLAYER){ - Player * _target = (Player *) target; - if (!p || p == _target) return 1; - } - return 0; +bool PlayerTargetChooser::canTarget(Targetable * target){ + return (target->typeAsTarget() == TARGET_PLAYER) && (!p || p == (Player*)target); } /*Damageable Target */ -int DamageableTargetChooser::canTarget(Targetable * target){ +bool DamageableTargetChooser::canTarget(Targetable * target){ if (target->typeAsTarget() == TARGET_PLAYER){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Targetting Player !!!\n"); #endif - return 1; + return true; } return CreatureTargetChooser::canTarget(target); } @@ -566,19 +556,18 @@ SpellTargetChooser::SpellTargetChooser(MTGCardInstance * card,int _color, int _m color = _color; } -int SpellTargetChooser::canTarget(Targetable * target){ +bool SpellTargetChooser::canTarget(Targetable * target){ MTGCardInstance * card = NULL; if (target->typeAsTarget() == TARGET_STACKACTION){ Interruptible * action = (Interruptible *) target; if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){ Spell * spell = (Spell *) action; card = spell->source; - if (card && (color == -1 || card->hasColor(color))) return 1; + if (card && (color == -1 || card->hasColor(color))) return true; } } - return 0; - + return false; } @@ -589,7 +578,7 @@ SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(MTGCardInstance * c color = _color; } -int SpellOrPermanentTargetChooser::canTarget(Targetable * target){ +bool SpellOrPermanentTargetChooser::canTarget(Targetable * target){ MTGCardInstance * card = NULL; if (target->typeAsTarget() == TARGET_CARD){ card = (MTGCardInstance *) target; @@ -599,12 +588,10 @@ int SpellOrPermanentTargetChooser::canTarget(Targetable * target){ if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){ Spell * spell = (Spell *) action; card = spell->source; - if (card && (color == -1 || card->hasColor(color))) return 1; + if (card && (color == -1 || card->hasColor(color))) return true; } } - - return 0; - + return false; } @@ -615,19 +602,17 @@ DamageTargetChooser::DamageTargetChooser(MTGCardInstance * card,int _color, int state = _state; } -int DamageTargetChooser::canTarget(Targetable * target){ +bool DamageTargetChooser::canTarget(Targetable * target){ MTGCardInstance * card = NULL; if (target->typeAsTarget() == TARGET_STACKACTION){ Interruptible * action = (Interruptible *) target; if (action->type == ACTION_DAMAGE && (action->state == state || state == -1)){ Damage * damage = (Damage *) action; card = damage->source; - if (card && (color == -1 || card->hasColor(color))) return 1; + if (card && (color == -1 || card->hasColor(color))) return true; } } - - return 0; - + return false; } @@ -638,7 +623,7 @@ DamageOrPermanentTargetChooser::DamageOrPermanentTargetChooser(MTGCardInstance * color = _color; } -int DamageOrPermanentTargetChooser::canTarget(Targetable * target){ +bool DamageOrPermanentTargetChooser::canTarget(Targetable * target){ MTGCardInstance * card = NULL; if (target->typeAsTarget() == TARGET_CARD){ card = (MTGCardInstance *) target; @@ -648,10 +633,8 @@ int DamageOrPermanentTargetChooser::canTarget(Targetable * target){ if (action->type == ACTION_DAMAGE){ Damage * damage = (Damage *) action; card = damage->source; - if (card && (color == -1 || card->hasColor(color))) return 1; + if (card && (color == -1 || card->hasColor(color))) return true; } } - - return 0; - + return false; } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index a97437064..c8c0ed808 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -64,7 +64,7 @@ int TestSuiteAI::Act(float dt){ string action = suite->getNextAction(); g->mLayers->stackLayer()->Dump(); - DamageResolverLayer * drl = g->mLayers->combatLayer(); + // DamageResolverLayer * drl = g->mLayers->combatLayer(); OutputDebugString(action.c_str()); OutputDebugString("\n"); @@ -90,6 +90,7 @@ int TestSuiteAI::Act(float dt){ g->userRequestNextGamePhase(); } else if (action.compare("next")==0){ + /* if (drl->orderingIsNeeded){ drl->blockersOrderingDone(); g->userRequestNextGamePhase(); @@ -100,6 +101,7 @@ int TestSuiteAI::Act(float dt){ }else{ g->userRequestNextGamePhase(); } + */ }else if (action.compare("yes")==0){ g->mLayers->stackLayer()->setIsInterrupting(this); }else if (action.compare("endinterruption")==0){ @@ -121,7 +123,7 @@ int TestSuiteAI::Act(float dt){ g->mLayers->actionLayer()->stuffHappened = 1; }else if(action.find("p1")!=string::npos || action.find("p2")!=string::npos){ Player * p = g->players[1]; - int start = action.find("p1"); + unsigned int start = action.find("p1"); if (start != string::npos) p = g->players[0]; g->cardClick(NULL, p); }else{ @@ -138,6 +140,7 @@ int TestSuiteAI::Act(float dt){ if (card) { OutputDebugString("Clicking ON: "); OutputDebugString(card->name.c_str()); + /* if (drl->mCount){ if (drl->orderingIsNeeded){ OutputDebugString(" Ordering Card\n"); @@ -149,6 +152,7 @@ int TestSuiteAI::Act(float dt){ }else{ g->cardClick(card,card); } + */ } } }else{ @@ -281,12 +285,12 @@ void TestSuite::initGame(){ for (int k = 0; k < initState.playerData[i].zones[j].nbitems; k++){ MTGCardInstance * card = getCardByMTGId(initState.playerData[i].zones[j].cards[k]); char buf[4096]; - sprintf(buf, "QUAD : %p\n", card->getQuad()); + sprintf(buf, "QUAD : %p\n", cache.getQuad(card)); OutputDebugString(buf); if (card && zone != p->game->library){ if (zone == p->game->inPlay){ MTGCardInstance * copy = p->game->putInZone(card, p->game->library, p->game->stack); - Spell * spell = NEW Spell(copy); + Spell * spell = NEW Spell(copy); spell->resolve(); if (!summoningSickness && p->game->inPlay->nb_cards>k) p->game->inPlay->cards[k]->summoningSickness = 0; delete spell; @@ -418,7 +422,7 @@ int TestSuite::loadNext(){ if (currentfile >= nbfiles) return 0; currentfile++; if (!load(files[currentfile-1].c_str())) return loadNext(); - + //load(files[currentfile].c_str()); //currentfile++; return currentfile; @@ -482,7 +486,7 @@ int TestSuite::load(const char * _filename){ int state = -1; - std::cout << std::endl << std::endl << "!!!" << file << std::endl << std::endl; + // std::cout << std::endl << std::endl << "!!!" << file << std::endl << std::endl; if(file){ cleanup(); while(std::getline(file,s)){ diff --git a/projects/mtg/src/TexturesCache.cpp b/projects/mtg/src/TexturesCache.cpp index f93435ec7..6a7d336f2 100644 --- a/projects/mtg/src/TexturesCache.cpp +++ b/projects/mtg/src/TexturesCache.cpp @@ -3,16 +3,15 @@ #include "../include/GameOptions.h" #include +TexturesCache cache; + TexturesCache::TexturesCache(){ nb_textures = 0; totalsize = 0; delete_previous = 0; lastTime = 0; - for (int i=0; ivalues[OPTIONS_CACHESIZE].getIntValue() * 100000; - if (!maxSize) maxSize = CACHE_SIZE_PIXELS; #ifdef WIN32 char buf [4096]; sprintf(buf, " Init TextureCache : %p\n", this); @@ -65,6 +64,8 @@ void TexturesCache::removeQuad(int id){ } int TexturesCache::cleanup(){ + int maxSize = options[Options::CACHESIZE].number * 100000; + if (!maxSize) maxSize = CACHE_SIZE_PIXELS; while (nb_textures >= MAX_CACHE_OBJECTS - 1 || totalsize > maxSize){ int i = getOldestQuad(); if (i == -1) return 0; @@ -76,7 +77,7 @@ int TexturesCache::cleanup(){ JQuad * TexturesCache::getQuad(MTGCard * card, int type){ int cache_id = getCacheById(card->getId(), type); if (cache_id == -1){ - + //Not found in the cache, we have to load the file and put it in the cache if (cleanup()){ cache_id = nb_textures; @@ -126,6 +127,7 @@ CardTexture::CardTexture(MTGCard * card, int _type): type(_type){ } if (tex){ quad = NEW JQuad(tex, 0.0f, 0.0f, tex->mWidth, tex->mHeight); + quad->SetHotSpot(tex->mWidth / 2, tex->mHeight / 2); nbpixels = tex->mTexHeight * tex->mTexWidth; } mtgid = card->getId(); @@ -200,4 +202,4 @@ SampleCache::~SampleCache(){ void SampleCache::DestroyInstance(){ SAFE_DELETE(mInstance); -} \ No newline at end of file +} diff --git a/projects/mtg/src/Token.cpp b/projects/mtg/src/Token.cpp index 0e83caf72..a32f33368 100644 --- a/projects/mtg/src/Token.cpp +++ b/projects/mtg/src/Token.cpp @@ -1,21 +1,19 @@ -#include "../include/Token.h" - -Token::Token(string _name, MTGCardInstance * source, int _power, int _toughness):MTGCardInstance(){ - isToken = true; - tokenSource = source; - power = _power; - toughness = _toughness; - life=toughness; - lifeOrig = life; - name = _name; - setMTGId(- source->getMTGId()); - setId = source->setId; +#include "../include/Token.h" + +Token::Token(string _name, MTGCardInstance * source, int _power, int _toughness):MTGCardInstance(){ + isToken = true; + tokenSource = source; + power = _power; + toughness = _toughness; + life=toughness; + lifeOrig = life; + name = _name; + setMTGId(- source->getMTGId()); + setId = source->setId; model = this; owner = source->owner; belongs_to=source->controller()->game; attacker = 0; defenser = NULL; banding = NULL; - mCache = source->mCache; - -} \ No newline at end of file +} diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index 341f1320f..27844179e 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -1,37 +1,26 @@ -#include "../include/WEvent.h" -#include "../include/MTGCardInstance.h" -#include "../include/MTGGameZones.h" -#include "../include/Damage.h" -#include "../include/PhaseRing.h" - - -WEvent::WEvent(int _type){ - type=_type; -} - -WEventZoneChange::WEventZoneChange(MTGCardInstance * _card, MTGGameZone * _from, MTGGameZone *_to):WEvent(CHANGE_ZONE){ - card = _card; - from = _from; - to = _to; -} - -WEventDamage::WEventDamage(Damage *_damage):WEvent(DAMAGE){ - damage = _damage; -} - -WEventPhaseChange::WEventPhaseChange(Phase * _from, Phase * _to):WEvent(CHANGE_PHASE){ - from = _from; - to = _to; -} - -WEventCardTap::WEventCardTap(MTGCardInstance * card, bool before, bool after) - :WEventCardUpdate(card), before(before), after(after){} - -WEventCreatureAttacker::WEventCreatureAttacker(MTGCardInstance * card,Targetable * before, Targetable * after) - :WEventCardUpdate(card), before(before), after(after){} - -WEventCreatureBlocker::WEventCreatureBlocker(MTGCardInstance * card,MTGCardInstance * from,MTGCardInstance * to) - :WEventCardUpdate(card), before(before), after(after){} - -WEventCreatureBlockerRank::WEventCreatureBlockerRank(MTGCardInstance * card,MTGCardInstance * exchangeWith, MTGCardInstance * attacker) - :WEventCardUpdate(card), exchangeWith(exchangeWith), attacker(attacker){} \ No newline at end of file +#include "../include/WEvent.h" +#include "../include/MTGCardInstance.h" +#include "../include/MTGGameZones.h" +#include "../include/Damage.h" +#include "../include/PhaseRing.h" + +WEvent::WEvent(int type) : type(type){} + +WEventZoneChange::WEventZoneChange(MTGCardInstance * card, MTGGameZone * from, MTGGameZone *to) : WEvent(CHANGE_ZONE), card(card), from(from), to(to){} + +WEventDamage::WEventDamage(Damage *damage) : WEvent(DAMAGE), damage(damage){} + +WEventCardUpdate::WEventCardUpdate(MTGCardInstance * card) : WEvent(), card(card) {}; + +WEventPhaseChange::WEventPhaseChange(Phase * from, Phase * to) : WEvent(CHANGE_PHASE), from(from), to(to){} + +WEventCardTap::WEventCardTap(MTGCardInstance * card, bool before, bool after) : WEventCardUpdate(card), before(before), after(after){} + +WEventCreatureAttacker::WEventCreatureAttacker(MTGCardInstance * card, Targetable * before, Targetable * after) : WEventCardUpdate(card), before(before), after(after){} + +WEventCreatureBlocker::WEventCreatureBlocker(MTGCardInstance * card, MTGCardInstance * from,MTGCardInstance * to) : WEventCardUpdate(card), before(before), after(after){} + +WEventCreatureBlockerRank::WEventCreatureBlockerRank(MTGCardInstance * card, MTGCardInstance * exchangeWith, MTGCardInstance * attacker) : WEventCardUpdate(card), exchangeWith(exchangeWith), attacker(attacker){} + +WEventEngageMana::WEventEngageMana(int color, MTGCardInstance* card) : WEvent(), color(color), card(card) {} +WEventConsumeMana::WEventConsumeMana(int color) : WEvent(), color(color) {}