- Added Momir Basic mode :)
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-04-04 12:52:36 +00:00
parent 82f418d0f3
commit 6582a1972a
24 changed files with 479 additions and 131 deletions

View File

@@ -1,4 +1,4 @@
OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIPlayer.o objs/AIStats.o objs/Blocker.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/ConstraintResolver.o objs/Counters.o objs/Damage.o objs/DamagerDamaged.o objs/DamageResolverLayer.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiCardsController.o objs/GuiLayers.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/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TexturesCache.o objs/Token.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/ConstraintResolver.o objs/Counters.o objs/Damage.o objs/DamagerDamaged.o objs/DamageResolverLayer.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiCardsController.o objs/GuiLayers.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/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TexturesCache.o objs/Token.o objs/utils.o objs/WEvent.o
DEPS = $(patsubst objs/%.o, deps/%.d, $(OBJS))
RESULT = $(shell psp-config --psp-prefix 2> Makefile.cache)

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,5 @@
Swamp *12
Island *12
Plains *12
Mountain *12
Forest *12

View File

@@ -0,0 +1,17 @@
#ifndef _AIMOMIRPLAYER_H_
#define _AIMOMIRPLAYER_H_
#include "AIPlayer.h"
class AIMomirPlayer:public AIPlayerBaka{
public:
AIMomirPlayer(MTGPlayerCards * _deck, char * file, char * avatarFile);
int getEfficiency(AIAction * action);
int momir();
int computeActions();
static MTGAbility * momirAbility;
static MTGAbility * getMomirAbility();
};
#endif

View File

@@ -71,6 +71,7 @@ class AIPlayer: public Player{
int selectAbility();
int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, map<AIAction *, int,CmpAbilities> * ranking);
int useAbility();
virtual int getEfficiency(AIAction * action);
};
@@ -84,7 +85,7 @@ class AIPlayerBaka: public AIPlayer{
AIPlayerBaka(MTGPlayerCards * _deck, char * deckFile, char * avatarFile);
virtual int Act(float dt);
void initTimer();
int computeActions();
virtual int computeActions();
};
class AIPlayerFactory{

View File

@@ -10,6 +10,7 @@
#include "GuiLayers.h"
#include "ActionElement.h"
#include "SimpleMenu.h"
#include "MTGAbility.h"
class GuiLayer;
class Targetable;
@@ -36,6 +37,7 @@ class ActionLayer: public GuiLayer, public JGuiListener{
void ButtonPressed(int controllerid, int controlid);
void doReactTo(int menuIndex);
TargetChooser * getCurrentTargetChooser();
MTGAbility * getAbility(int type);
};

View File

@@ -41,6 +41,9 @@
#define PLAYER_TYPE_TESTSUITE 2
#define GAME_TYPE_CLASSIC 0
#define GAME_TYPE_MOMIR 1
class MTGAllCards;
class TexturesCache;
@@ -63,6 +66,7 @@ class GameApp: public JApp
public:
int players[2];
MTGAllCards * collection;
int gameType;
TexturesCache * cache;
GameApp();

View File

@@ -9,6 +9,7 @@ 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_DIFFICULTY "difficulty"
// WALDORF - added

View File

@@ -33,7 +33,9 @@ class GameStateDuel: public GameState, public JGuiListener
JQuad * unlockedQuad;
JTexture * unlockedTex;
int isDifficultyUnlocked();
int isMomirUnlocked();
void loadPlayer(int playerId, int decknb = 0, int isAI = 0);
void loadPlayerMomir(int playerId, int isAI);
public:
GameStateDuel(GameApp* parent);
virtual ~GameStateDuel();

View File

@@ -11,6 +11,8 @@ class GameStateMenu: public GameState, public JGuiListener
private:
JGuiController* mGuiController;
SimpleMenu* subMenuController;
SimpleMenu* gameTypeMenu;
int hasChosenGameType;
JQuad * mIcons[10];
JTexture * mIconsTexture;
JTexture * bgTexture;

View File

@@ -60,12 +60,16 @@ class MTGAbility: public ActionElement{
virtual int resolve(){return 0;};
/*Poor man's casting */
/* Todo replace that crap with dynamic casting */
enum {
UNKNOWN = 0,
MANA_PRODUCER = 1,
MTG_ATTACK_RULE = 2,
DAMAGER = 3,
STANDARD_REGENERATE = 4,
PUT_INTO_PLAY = 5,
MOMIR = 6,
MTG_BLOCK_RULE = 7,
};
};

View File

@@ -85,6 +85,7 @@ class MTGPlayerCards {
MTGInPlay * inPlay;
MTGStack * stack;
MTGRemovedFromGame * removedFromGame;
MTGGameZone * garbage;
MTGAllCards * collection;

View File

@@ -81,62 +81,6 @@ OutputDebugString("Receive5\n");
};
/*
class MTGPersistRule:public ListMaintainerAbility{
public:
MTGPersistRule(int _id):ListMaintainerAbility(_id){};
virtual void Update(float dt){
map<MTGCardInstance *,bool>::iterator it;
for ( it=cards.begin() ; it != cards.end(); it++ ){
MTGCardInstance * card = ((*it).first);
Player * p = card->controller();
if (p->game->graveyard->hasCard(card)){
p->game->putInZone(card, p->game->graveyard, p->game->hand);
Spell * spell = NEW Spell(card);
p->game->putInZone(card, p->game->hand, p->game->stack);
spell->resolve();
delete spell;
card->counters->addCounter(-1,-1);
}
}
// Dirtiest Code Ever, we remove the counters here
for (int i = 0; i < 2; i++){
Player * p = game->players[i];
MTGGameZone * zones[] = {p->game->graveyard, p->game->hand, p->game->library, p->game->removedFromGame};
for (int j = 0; j < 5; j++){
MTGGameZone * zone = zones[j];
for (int k=0; k < zone->nb_cards; k++){
zone->cards[k]->counters->init();
}
}
}
ListMaintainerAbility::Update(dt);
}
int canBeInList(MTGCardInstance * card){
if (card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1) ){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("yay, persist !\n");
#endif
return 1;
}
return 0;
}
int added(MTGCardInstance * card){return 1;}
int removed(MTGCardInstance * card){return 0;}
int testDestroy(){return 0;}
};
*/
/*
* Rule 420.5e (Legend Rule)
@@ -176,4 +120,18 @@ class MTGLegendRule:public ListMaintainerAbility{
int testDestroy(){return 0;}
};
class MTGMomirRule:public MTGAbility{
public:
int alreadyplayed;
MTGAllCards * collection;
MTGCardInstance * genRandomCreature(int convertedCost);
int testDestroy();
void Update(float dt);
MTGMomirRule(int _id, MTGAllCards * _collection);
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
int reactToClick(MTGCardInstance * card);
const char * getMenuText(){return "Momir";}
};
#endif

View File

@@ -22,7 +22,7 @@ class ManaCost{
static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL);
void init();
void x();
ManaCost(int _cost[], int nb_elems);
ManaCost(int _cost[], int nb_elems = 1);
ManaCost();
~ManaCost();
ManaCost(ManaCost * _manaCost);

View File

@@ -0,0 +1,192 @@
#include "../include/config.h"
#include "../include/AIMomirPlayer.h"
#include "../include/CardDescriptor.h"
#include "../include/DamageResolverLayer.h"
#include "../include/DamagerDamaged.h"
#include "../include/AIStats.h"
#include "../include/AllAbilities.h"
MTGAbility * AIMomirPlayer::momirAbility = NULL;
AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * _deck, char * file, char * avatarFile): AIPlayerBaka(_deck,file, avatarFile){
// TODO count min and max number of mana (should probably be part of the gameobserver so that human players don't make mistakes)
momirAbility = NULL;
}
int AIMomirPlayer::getEfficiency(AIAction * action){
int efficiency = AIPlayerBaka::getEfficiency(action);
if (efficiency < 15) return 0;
GameObserver * g = GameObserver::GetInstance();
if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0;
return efficiency;
}
MTGAbility * AIMomirPlayer::getMomirAbility(){
if (momirAbility) return momirAbility;
GameObserver * g = GameObserver::GetInstance();
momirAbility = g->mLayers->actionLayer()->getAbility(MTGAbility::MOMIR);
return momirAbility;
}
int AIMomirPlayer::momir(){
if (!game->hand->nb_cards) return 0; //nothing to discard :/
getPotentialMana();
int converted = potentialMana->getConvertedCost();
int efficiency = 100;
int chance = 1 + (rand() % 100);
if (converted == 5) efficiency = 5 ; //Strategy: skip 5 drop
if (converted == 7) efficiency = 50; //Strategy: 7 drops have bad upkeep costs and the AI doesn't handle those right now...
if (converted > 8 ) converted = 8;
if (converted == 8) efficiency = 100 - game->inPlay->nb_cards;
if (efficiency >= chance){
int _cost[] = {Constants::MTG_COLOR_ARTIFACT,converted};
ManaCost * cost = NEW ManaCost(_cost);
tapLandsForMana(potentialMana,cost);
delete cost;
MTGAbility * ability = getMomirAbility();
MTGCardInstance * card = game->hand->cards[0];
if (ability->isReactingToClick(card,cost)){
AIAction * a = NEW AIAction(ability,card);
clickstream.push(a);
return 1;
}
}
return 0;
}
int AIMomirPlayer::computeActions(){
//Part of the strategy goes here. When should we put a land into play ?
/*
Another gift from Alex Majlaton on my first day playing Momir, and it has served me well ever since. It goes a little something like this: (a) if you are on the play, hit your Two through Four, skip your Five, and then hit all the way to Eight; (b) if you are on the draw and your opponent skips his One, you make Two through Eight; (c) if you are on the draw and your opponent hits a One, you match him drop-for-drop for the rest of the game.
You skip your Five on the play because it is the weakest drop. There are plenty of serviceable guys there, but very few bombs compared to other drops
the general rule is this: if you want to get to Eight, you have to skip two drops on the play and one drop on the draw.
*/
GameObserver * g = GameObserver::GetInstance();
Player * p = g->currentPlayer;
if (!(g->currentlyActing() == this)) return 0;
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;
//No mana, try to get some
getPotentialMana();
switch(currentGamePhase){
case Constants::MTG_PHASE_FIRSTMAIN:
if (canPutLandsIntoPlay && (potentialMana->getConvertedCost() <8 || game->hand->nb_cards > 1) ){
//Attempt to put land into play
cd.init();
cd.setColor(Constants::MTG_COLOR_LAND);
card = cd.match(game->hand);
if (card){
MTGAbility * putIntoPlay = g->mLayers->actionLayer()->getAbility(MTGAbility::PUT_INTO_PLAY);
AIAction * a = NEW AIAction(putIntoPlay,card); //TODO putinplay action
clickstream.push(a);
return 1;
}
}
momir();
return 1;
break;
case Constants::MTG_PHASE_SECONDMAIN:
selectAbility();
return 1;
break;
default:
return AIPlayerBaka::computeActions();
break;
}
}else{
return AIPlayerBaka::computeActions();
}
}
/*
int AIPlayerBaka::computeActions(){
GameObserver * g = GameObserver::GetInstance();
Player * p = g->currentPlayer;
if (!(g->currentlyActing() == this)) return 0;
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;
};
*/

View File

@@ -121,6 +121,10 @@ ManaCost * AIPlayer::getPotentialMana(){
}
int AIPlayer::getEfficiency(AIAction * action){
return action->getEfficiency();
}
int AIAction::getEfficiency(){
//TODO add multiplier according to what the player wants
if (efficiency != -1) return efficiency;
@@ -129,6 +133,7 @@ int AIAction::getEfficiency(){
ActionStack * s = g->mLayers->stackLayer();
Player * p = g->currentlyActing();
if (s->has(ability)) return 0;
if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet
switch (ability->aType){
case MTGAbility::DAMAGER:
{
@@ -226,7 +231,7 @@ int AIPlayer::selectAbility(){
OutputDebugString("We have a winner\n");
AIAction * a = ranking.begin()->first;
int chance = 1 + rand() % 100;
if (a->getEfficiency() < chance){
if (getEfficiency(a) < chance){
a = NULL;
}else{
OutputDebugString("We REALLY have a winner\n");
@@ -262,6 +267,8 @@ int AIPlayer::effectBadOrGood(MTGCardInstance * card){
return BAKA_EFFECT_DONTKNOW;
}
int AIPlayer::chooseTarget(TargetChooser * tc){
Targetable * potentialTargets[50];
int nbtargets = 0;
@@ -393,24 +400,25 @@ int AIPlayer::chooseBlockers(){
cd.setType("Creature");
cd.tapped = -1;
MTGCardInstance * card = NULL;
GameObserver * g = GameObserver::GetInstance();
while((card = cd.nextmatch(game->inPlay, card))){
GameObserver::GetInstance()->cardClick(card);
g->cardClick(card);
if (g->mLayers->actionLayer()->menuObject) g->mLayers->actionLayer()->doReactTo(0);
int set = 0;
while(!set){
if (!card->defenser){
set = 1;
set = 1;
}else{
MTGCardInstance * attacker = card->defenser;
map<MTGCardInstance *,int>::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{
GameObserver * g = GameObserver::GetInstance();
MTGCardInstance * attacker = card->defenser;
map<MTGCardInstance *,int>::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->cardClick(card);
if (g->mLayers->actionLayer()->menuObject) g->mLayers->actionLayer()->doReactTo(0);
}
@@ -421,7 +429,7 @@ int AIPlayer::chooseBlockers(){
while((card = cd.nextmatch(game->inPlay, card))){
if (card->defenser && opponentsToughness[card->defenser] > 0){
while (card->defenser){
GameObserver * g = GameObserver::GetInstance();
g->cardClick(card);
if (g->mLayers->actionLayer()->menuObject) g->mLayers->actionLayer()->doReactTo(0);
}
@@ -430,7 +438,6 @@ int AIPlayer::chooseBlockers(){
card = NULL;
while((card = cd.nextmatch(game->inPlay, card))){
if(!card->defenser){
GameObserver * g = GameObserver::GetInstance();
g->cardClick(card);
if (g->mLayers->actionLayer()->menuObject) g->mLayers->actionLayer()->doReactTo(0);
int set = 0;
@@ -440,7 +447,6 @@ int AIPlayer::chooseBlockers(){
}else{
MTGCardInstance * attacker = card->defenser;
if (opponentsToughness[attacker] <= 0 || (card->toughness <= card->defenser->power && opponentForce*2 <life) || card->defenser->nbOpponents()>1){
GameObserver * g = GameObserver::GetInstance();
g->cardClick(card);
if (g->mLayers->actionLayer()->menuObject) g->mLayers->actionLayer()->doReactTo(0);
}else{

View File

@@ -4,6 +4,16 @@
#include "../include/Targetable.h"
#include "../include/WEvent.h"
MTGAbility* ActionLayer::getAbility(int type){
for (int i = 1; i < mCount; i++){
MTGAbility * a = ((MTGAbility *)mObjects[i]);
if (a->aType == type){
return a;
}
}
return NULL;
}
int ActionLayer::unstopableRenderInProgress(){
for (int i=0;i<mCount;i++){

View File

@@ -38,8 +38,8 @@ GameApp::GameApp(): JApp()
mShowDebugInfo = false;
players[0] = 0;
players[1] = 0;
gameType = GAME_TYPE_CLASSIC;
//gameType = GAME_TYPE_MOMIR;
}

View File

@@ -109,6 +109,10 @@ void GameObserver::nextGamePhase(){
}
mLayers->stackLayer()->garbageCollect(); //clean stack history for this turn;
mLayers->actionLayer()->Update(0);
for (int i=0; i < 2; i++){
delete (players[i]->game->garbage);
players[i]->game->garbage = NEW MTGGameZone();
}
return nextGamePhase();
}

View File

@@ -3,9 +3,10 @@
#include "../include/GameOptions.h"
#include "../include/utils.h"
#include "../include/AIPlayer.h"
#include "../include/AIMomirPlayer.h"
#include "../include/PlayerData.h"
#include "../include/DeckStats.h"
#include "../include/MTGRules.h"
#ifdef TESTSUITE
#include "../include/TestSuiteAI.h"
@@ -89,18 +90,18 @@ void GameStateDuel::Start()
for (int i = 0; i<2; i ++){
if (mParent->players[i] == PLAYER_TYPE_HUMAN){
if (!deckmenu){
decksneeded = 1;
deckmenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_DECK, this, mFont, 35, 25, "Choose a Deck");
char buffer[100];
for (int j=1; j<6; j++){
sprintf(buffer, RESPATH"/player/deck%i.txt",j);
std::ifstream file(buffer);
if(file){
deckmenu->Add(j, GameState::menuTexts[j]);
file.close();
decksneeded = 0;
}
}
decksneeded = 1;
deckmenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_DECK, this, mFont, 35, 25, "Choose a Deck");
char buffer[100];
for (int j=1; j<6; j++){
sprintf(buffer, RESPATH"/player/deck%i.txt",j);
std::ifstream file(buffer);
if(file){
deckmenu->Add(j, GameState::menuTexts[j]);
file.close();
decksneeded = 0;
}
}
}
}
}
@@ -110,6 +111,19 @@ void GameStateDuel::Start()
}
void GameStateDuel::loadPlayerMomir(int playerId, int isAI){
char * deckFile = RESPATH"/player/momir.txt";
char * deckFileSmall = "momir";
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],deckFileSmall);
}else{
mPlayers[playerId] = NEW AIMomirPlayer(deck[playerId],deckFile,"");
}
delete tempDeck;
}
void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI){
if (decknb){
if (!isAI){ //Human Player
@@ -197,7 +211,14 @@ void GameStateDuel::Update(float dt)
mParent->SetNextState(GAME_STATE_DECK_VIEWER);
break;
case DUEL_STATE_CHOOSE_DECK1:
if (mParent->players[0] == PLAYER_TYPE_HUMAN)
if (mParent->gameType == GAME_TYPE_MOMIR){
for (int i = 0; i < 2; i++){
int isAI = 1;
if (mParent->players[i] == PLAYER_TYPE_HUMAN) isAI = 0;
loadPlayerMomir(i, isAI);
}
mGamePhase = DUEL_STATE_PLAY;
}else if (mParent->players[0] == PLAYER_TYPE_HUMAN)
deckmenu->Update(dt);
#ifdef TESTSUITE
else if (mParent->players[1] == PLAYER_TYPE_TESTSUITE){
@@ -280,13 +301,19 @@ void GameStateDuel::Update(float dt)
case DUEL_STATE_PLAY:
//Stop the music before starting the game
if (GameApp::music){
JSoundSystem::GetInstance()->StopMusic(GameApp::music);
SAFE_DELETE(GameApp::music);
JSoundSystem::GetInstance()->StopMusic(GameApp::music);
SAFE_DELETE(GameApp::music);
}
if (!game){
GameObserver::Init(mPlayers, 2);
game = GameObserver::GetInstance();
game->startGame();
GameObserver::Init(mPlayers, 2);
game = GameObserver::GetInstance();
game->startGame();
if (mParent->gameType == GAME_TYPE_MOMIR){
game->addObserver(NEW MTGMomirRule(-1, mParent->collection));
for (int i = 0; i < 2; i++){
game->players[i]->life+=4;
}
}
}
game->Update(dt);
if (game->gameOver){
@@ -303,6 +330,16 @@ void GameStateDuel::Update(float dt)
unlockedQuad = NEW JQuad(unlockedTex, 2, 2, 396, 96);
GameOptions::GetInstance()->values[OPTIONS_DIFFICULTY_MODE_UNLOCKED] = GameOption(1);
GameOptions::GetInstance()->save();
}else{
unlocked = isMomirUnlocked();
if (unlocked){
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();
}
}
if (unlocked){
JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/bonus.wav");
if (sample) JSoundSystem::GetInstance()->PlaySample(sample);
}
@@ -496,4 +533,11 @@ int GameStateDuel::isDifficultyUnlocked(){
}
}
return 0;
}
int GameStateDuel::isMomirUnlocked(){
if (GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()) return 0;
Player *p = mPlayers[0];
if (p->game->inPlay->countByType("land") == 8) return 1;
return 0;
}

View File

@@ -47,7 +47,9 @@ enum
SUBMENUITEM_2PLAYER,
SUBMENUITEM_DEMO,
SUBMENUITEM_CANCEL,
SUBMENUITEM_TESTSUITE
SUBMENUITEM_TESTSUITE,
SUBMENUITEM_MOMIR,
SUBMENUITEM_CLASSIC,
};
@@ -55,6 +57,7 @@ GameStateMenu::GameStateMenu(GameApp* parent): GameState(parent)
{
mGuiController = NULL;
subMenuController = NULL;
gameTypeMenu = NULL;
mIconsTexture = NULL;
//bgMusic = NULL;
timeIndex = 0;
@@ -118,6 +121,7 @@ void GameStateMenu::Destroy()
{
SAFE_DELETE(mGuiController);
SAFE_DELETE(subMenuController);
SAFE_DELETE(gameTypeMenu);
SAFE_DELETE(mIconsTexture);
for (int i = 0; i < 10 ; i++){
@@ -148,6 +152,9 @@ void GameStateMenu::Start(){
JSoundSystem::GetInstance()->StopMusic(GameApp::music);
SAFE_DELETE(GameApp::music);
}
hasChosenGameType = 1;
if (GameOptions::GetInstance()->values[OPTIONS_MOMIR_MODE_UNLOCKED].getIntValue()) hasChosenGameType =0;
}
@@ -176,13 +183,7 @@ int GameStateMenu::nextCardSet(){
void GameStateMenu::End()
{
//mEngine->EnableVSync(false);
// if (bgMusic)
// {
//JSoundSystem::GetInstance()->StopMusic(bgMusic);
//SAFE_DELETE(bgMusic);
// }
JRenderer::GetInstance()->EnableVSync(false);
}
@@ -190,14 +191,6 @@ void GameStateMenu::End()
void GameStateMenu::Update(float dt)
{
/*
if (GameApp::music){
if (mVolume < 2*GameOptions::GetInstance()->values[OPTIONS_MUSICVOLUME]){
mVolume++;
JSoundSystem::GetInstance()->SetVolume(mVolume/2);
}
}
*/
timeIndex += dt * 2;
switch (MENU_STATE_MAJOR & currentState)
@@ -258,8 +251,19 @@ void GameStateMenu::Update(float dt)
case MENU_STATE_MAJOR_DUEL :
if (MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR))
{
mParent->SetNextState(GAME_STATE_DUEL);
currentState = MENU_STATE_MAJOR_MAINMENU;
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");
subMenuController->Add(SUBMENUITEM_MOMIR, "Momir Basic");
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel");
}
}else{
mParent->SetNextState(GAME_STATE_DUEL);
currentState = MENU_STATE_MAJOR_MAINMENU;
}
}
}
switch (MENU_STATE_MINOR & currentState)
@@ -423,23 +427,18 @@ JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MENU_FONT);
switch (controlId)
{
case MENUITEM_PLAY:
subMenuController = NEW SimpleMenu(102, this, mFont, 150,60);
if (subMenuController){
subMenuController->Add(SUBMENUITEM_1PLAYER,"1 Player");
subMenuController->Add(SUBMENUITEM_2PLAYER, "2 Players");
subMenuController->Add(SUBMENUITEM_DEMO,"Demo");
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel");
#ifdef TESTSUITE
subMenuController = NEW SimpleMenu(102, this, mFont, 150,60);
#else
subMenuController = NEW SimpleMenu(102, this, mFont, 150,60);
#endif
if (subMenuController){
subMenuController->Add(SUBMENUITEM_1PLAYER,"1 Player");
subMenuController->Add(SUBMENUITEM_2PLAYER, "2 Players");
subMenuController->Add(SUBMENUITEM_DEMO,"Demo");
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel");
#ifdef TESTSUITE
subMenuController->Add(SUBMENUITEM_TESTSUITE, "Test Suite");
subMenuController->Add(SUBMENUITEM_TESTSUITE, "Test Suite");
#endif
currentState = MENU_STATE_MAJOR_SUBMENU | MENU_STATE_MINOR_NONE;
}
break;
}
break;
case MENUITEM_DECKEDITOR:
mParent->SetNextState(GAME_STATE_DECK_VIEWER);
break;
@@ -474,6 +473,20 @@ JLBFont * mFont = GameApp::CommonRes->GetJLBFont(Constants::MENU_FONT);
subMenuController->Close();
currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING;
break;
case SUBMENUITEM_CLASSIC:
this->hasChosenGameType = 1;
mParent->gameType = GAME_TYPE_CLASSIC;
subMenuController->Close();
currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING;
break;
case SUBMENUITEM_MOMIR:
this->hasChosenGameType = 1;
mParent->gameType = GAME_TYPE_MOMIR;
subMenuController->Close();
currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING;
break;
#ifdef TESTSUITE
case SUBMENUITEM_TESTSUITE:
mParent->players[0] = PLAYER_TYPE_TESTSUITE;

View File

@@ -54,6 +54,7 @@ MTGPlayerCards::~MTGPlayerCards(){
SAFE_DELETE(inPlay);
SAFE_DELETE(stack);
SAFE_DELETE(removedFromGame);
SAFE_DELETE(garbage);
}
void MTGPlayerCards::setOwner(Player * player){
@@ -82,6 +83,7 @@ void MTGPlayerCards::init(){
inPlay = NEW MTGInPlay();
stack = NEW MTGStack();
removedFromGame = NEW MTGRemovedFromGame();
garbage = NEW MTGGameZone();
}
@@ -130,8 +132,7 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
if (card->isToken){
if (to != g->players[0]->game->inPlay && to != g->players[1]->game->inPlay){
//Token leaves play: we destroy it
//TODO DELETE Object
garbage->addCard(copy);
return NULL;
}
}

View File

@@ -2,7 +2,7 @@
#include "../include/MTGRules.h"
MTGPutInPlayRule::MTGPutInPlayRule(int _id):MTGAbility(_id, NULL){
aType=MTGAbility::PUT_INTO_PLAY;
}
int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
@@ -78,6 +78,7 @@ int MTGPutInPlayRule::testDestroy(){
}
MTGAttackRule::MTGAttackRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_ATTACK_RULE;
}
int MTGAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
@@ -102,6 +103,7 @@ int MTGAttackRule::testDestroy(){
MTGBlockRule::MTGBlockRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_BLOCK_RULE;
}
int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
@@ -134,3 +136,74 @@ int MTGBlockRule::reactToClick(MTGCardInstance * card){
int MTGBlockRule::testDestroy(){
return 0;
}
//
// * Momir
//
MTGMomirRule::MTGMomirRule(int _id, MTGAllCards * _collection):MTGAbility(_id, NULL){
collection = _collection;
alreadyplayed = 0;
aType=MTGAbility::MOMIR;
}
int MTGMomirRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
if (alreadyplayed) return 0;
Player * player = game->currentlyActing();
Player * currentPlayer = game->currentPlayer;
LOG("CANPUTINPLAY- check if card belongs to current player\n");
if (!player->game->hand->hasCard(card)) return 0;
LOG("CANPUTINPLAY- check if card is land or can be played\n");
if (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)){
LOG("CANPUTINPLAY- correct time to play\n");
return 1;
}
return 0;
}
int MTGMomirRule::reactToClick(MTGCardInstance * card_to_discard){
if (!isReactingToClick(card_to_discard)) return 0;
Player * player = game->currentlyActing();
ManaCost * cost = player->getManaPool();
int converted = cost->getConvertedCost();
player->getManaPool()->pay(cost);
player->game->putInZone(card_to_discard, player->game->hand, player->game->graveyard);
MTGCardInstance * card = genRandomCreature(converted); //TODO code this function
player->game->stack->addCard(card);
Spell * spell = NEW Spell(card);
spell->resolve();
spell->source->isToken = 1;
delete spell;
alreadyplayed = 1;
return 1;
}
MTGCardInstance * MTGMomirRule::genRandomCreature(int convertedCost){
Player * p = game->currentlyActing();
int total_cards = collection->totalCards();
int start = (rand() % total_cards);
int id2 = start;
while (id2 < total_cards){
MTGCard * card = collection->collection[id2];
if (card->isACreature() && card->getManaCost()->getConvertedCost() == convertedCost){
return NEW MTGCardInstance(card,p->game);
}
id2++;
if (id2 == start) return NULL;
if (id2 == total_cards) id2 = 0;
}
return NULL;
}
//The Momir rule is never destroyed
int MTGMomirRule::testDestroy(){
return 0;
}
void MTGMomirRule::Update(float dt){
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){
alreadyplayed = 0;
}
MTGAbility::Update(dt);
}

View File

@@ -228,6 +228,10 @@
RelativePath=".\src\ActionStack.cpp"
>
</File>
<File
RelativePath=".\src\AIMomirPlayer.cpp"
>
</File>
<File
RelativePath=".\src\AIPlayer.cpp"
>
@@ -529,6 +533,10 @@
RelativePath=".\include\ActionStack.h"
>
</File>
<File
RelativePath=".\include\AIMomirPlayer.h"
>
</File>
<File
RelativePath=".\include\AIPlayer.h"
>