diff --git a/projects/mtg/include/CardGui.h b/projects/mtg/include/CardGui.h index a732c6b3a..f030c810a 100644 --- a/projects/mtg/include/CardGui.h +++ b/projects/mtg/include/CardGui.h @@ -32,6 +32,7 @@ struct CardGui : public PlayGuiObject { void renderCountersBig(const Pos& pos); virtual void Update(float dt); static void alternateRender(MTGCard * card, const Pos& pos); + static void tinyCropRender(MTGCard * card, const Pos& pos, JQuad * quad); static JQuad * alternateThumbQuad(MTGCard * card); virtual ostream& toString(ostream&) const; }; diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index 236c368ce..79d9363e2 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -53,6 +53,15 @@ public: class MTGSets{ public: + + //These values have to be < 0 + // A setID with a value >=0 will be looked into the sets table, + // Negative values will be compared to these enums throughout the code (shop, filters...) + enum { + INTERNAL_SET = -1, + ALL_SETS = -2, + }; + friend class MTGSetInfo; MTGSets(); ~MTGSets(); diff --git a/projects/mtg/include/WFilter.h b/projects/mtg/include/WFilter.h index 3d9c4c4a7..95221ac7b 100644 --- a/projects/mtg/include/WFilter.h +++ b/projects/mtg/include/WFilter.h @@ -85,9 +85,9 @@ public: //Filter terminals: class WCFilterSet: public WCardFilter{ public: - WCFilterSet(int _setid=-1) {setid=_setid;}; + WCFilterSet(int _setid=MTGSets::ALL_SETS) {setid=_setid;}; WCFilterSet(string arg); - bool isMatch(MTGCard *c) {return (setid==-1 || c->setId == setid);}; + bool isMatch(MTGCard *c) {return (setid==MTGSets::ALL_SETS || c->setId == setid);}; string getCode(); float filterFee() {return 0.2f;}; protected: diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index e558c4215..82b7a7d6f 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -1,3 +1,8 @@ +/* + * CardGui.cpp + * This class is in charge of rendering Cards on the screen + */ + #include "JGE.h" #include "../include/config.h" #include "../include/CardGui.h" @@ -349,11 +354,215 @@ void CardGui::alternateRender(MTGCard * card, const Pos& pos){ font->SetScale(backup_scale); } + +void CardGui::tinyCropRender(MTGCard * card, const Pos& pos, JQuad * quad) { + + if (!quad) return; + + JRenderer * renderer = JRenderer::GetInstance(); + JQuad * q; + + float x = pos.actX; + float displayScale = 250 / BigHeight; + + if(card->data->countColors() > 1) { + q = resources.RetrieveTempQuad("gold.jpg"); + } else { + switch(card->data->getColor()) + { + case Constants::MTG_COLOR_ARTIFACT: q = resources.RetrieveTempQuad("artifact.jpg");break; + case Constants::MTG_COLOR_GREEN: q = resources.RetrieveTempQuad("green.jpg");break; + case Constants::MTG_COLOR_BLUE : q = resources.RetrieveTempQuad("blue.jpg");break; + case Constants::MTG_COLOR_RED : q = resources.RetrieveTempQuad("red.jpg");break; + case Constants::MTG_COLOR_BLACK: q = resources.RetrieveTempQuad("black.jpg");break; + case Constants::MTG_COLOR_WHITE: q = resources.RetrieveTempQuad("white.jpg");break; + case Constants::MTG_COLOR_LAND: q = resources.RetrieveTempQuad("land.jpg");break; + default: q = resources.RetrieveTempQuad("gold.jpg");break; + } + } + if(q && q->mTex){ + q->SetHotSpot(q->mTex->mWidth/2,q->mTex->mHeight/2); + + float scale = pos.actZ * displayScale * BigHeight / q->mHeight; + q->SetColor(ARGB((int)pos.actA,255,255,255)); + renderer->RenderQuad(q, x, pos.actY, pos.actT, scale, scale); + } + + const std::vector txt = card->data->formattedText(); + size_t nbTextLines = txt.size(); + + //Render the image on top of that + quad->SetColor(ARGB((int)pos.actA,255,255,255)); + float imgScale = pos.actZ * (displayScale * (BigWidth - 15)) / quad->mWidth; + float imgY = pos.actY - (20 * imgScale); + if (nbTextLines > 6) { + imgY -= 10 * imgScale; + imgScale *= 0.75; + } + renderer->RenderQuad(quad, x, imgY , pos.actT, imgScale, imgScale); + + // Write the title + WFont * font = resources.GetWFont("magic"); + float backup_scale = font->GetScale(); + font->SetColor(ARGB((int)pos.actA, 0, 0, 0)); + font->SetScale(0.8 * pos.actZ); + + { + char name[4096]; + sprintf(name, "%s", _(card->data->getName()).c_str()); + float w = font->GetStringWidth(name) * 0.8 * pos.actZ; + if (w > BigWidth - 30) + font->SetScale((BigWidth - 30) / w); + font->DrawString(name, x + (22 - BigWidth / 2)*pos.actZ, pos.actY + (25 - BigHeight / 2)*pos.actZ); + } + + // Write the description + { + font->SetScale(0.8 * pos.actZ); + float imgBottom = imgY + (imgScale * quad->mHeight/2); + unsigned i = 0; + unsigned h = neofont ? 14 : 11; + for (std::vector::const_iterator it = txt.begin(); it != txt.end(); ++it, ++i) + font->DrawString(it->c_str(), x + (22 - BigWidth / 2)*pos.actZ, imgBottom + (h * i*pos.actZ)); + } + + // Write the strength + if (card->data->isCreature()) + { + char buffer[32]; + sprintf(buffer, "%i/%i", card->data->power, card->data->toughness); + float w = font->GetStringWidth(buffer) * 0.8; + font->DrawString(buffer, x + (65 - w / 2)*pos.actZ, pos.actY + (106)*pos.actZ); + } + + // Mana + { + ManaCost* manacost = card->data->getManaCost(); + ManaCostHybrid* h; + unsigned int j = 0; + unsigned char t = (JGE::GetInstance()->GetTime() / 3) & 0xFF; + unsigned char v = t + 127; + float yOffset = -112; + 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], x + (-12 * j + 75 + 3 * sinf(2*M_PI*((float)t)/256.0))*pos.actZ, pos.actY + (yOffset + 3 * cosf(2*M_PI*((float)(t-35))/256.0))*pos.actZ, 0, 0.4 + scale, 0.4 + scale); + renderer->RenderQuad(manaIcons[h->color2], x + (-12 * j + 75 + 3 * sinf(2*M_PI*((float)v)/256.0))*pos.actZ, pos.actY + (yOffset + 3 * cosf(2*M_PI*((float)(v-35))/256.0))*pos.actZ, 0, 0.4 - scale, 0.4 - scale); + } + else + { + renderer->RenderQuad(manaIcons[h->color2], x + (- 12 * j + 75 + 3 * sinf(2*M_PI*((float)v)/256.0))*pos.actZ, pos.actY + (yOffset + 3 * cosf(2*M_PI*((float)(v-35))/256.0))*pos.actZ, 0, 0.4 - scale, 0.4 - scale); + renderer->RenderQuad(manaIcons[h->color1], x + (- 12 * j + 75 + 3 * sinf(2*M_PI*((float)t)/256.0))*pos.actZ, pos.actY + (yOffset + 3 * cosf(2*M_PI*((float)(t-35))/256.0))*pos.actZ, 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], x + (-12*j + 75)*pos.actZ, pos.actY + (yOffset)*pos.actZ, 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], x + (- 12*j + 75)*pos.actZ, pos.actY +(yOffset)*pos.actZ, 0, 0.4 * pos.actZ, 0.4 * pos.actZ); + float w = font->GetStringWidth(buffer); + font->DrawString(buffer, x +(- 12*j + 76 - w/2)*pos.actZ, pos.actY + (yOffset - 5)*pos.actZ); + ++j; + } + //Has X? + if (int cost = manacost->hasX()) + { + char buffer[10]; + sprintf(buffer, "X"); + renderer->RenderQuad(manaIcons[0], x + (- 12*j + 75)*pos.actZ, pos.actY +(yOffset)*pos.actZ, 0, 0.4 * pos.actZ, 0.4 * pos.actZ); + float w = font->GetStringWidth(buffer); + font->DrawString(buffer, x +(- 12*j + 76 - w/2)*pos.actZ, pos.actY + (yOffset - 5)*pos.actZ); + } + } + + //types + { + string s = ""; + for (int i = card->data->types.size() - 1; i > 0; --i) + { + s += _(Subtypes::subtypesList->find(card->data->types[i])); + s += _(" - "); + } + if(card->data->types.size()) + s += _(Subtypes::subtypesList->find(card->data->types[0])); +#ifdef _DEBUG + else{ + char buf[2048]; + sprintf(buf, "Typeless card: %s %s (%i)\n", setlist[card->setId].c_str(), card->data->getName().c_str(), card->getId()); + OutputDebugString(buf); + } +#endif + + font->DrawString(s.c_str(), x + (22 - BigWidth / 2)*pos.actZ, pos.actY + (49 - BigHeight / 2)*pos.actZ); + } + + //expansion and rarity + font->SetColor(ARGB((int)pos.actA, 0, 0, 0)); + { + char buf[512]; + switch(card->getRarity()){ + case Constants::RARITY_M: + sprintf(buf,_("%s Mythic").c_str(),setlist[card->setId].c_str()); + break; + case Constants::RARITY_R: + sprintf(buf,_("%s Rare").c_str(),setlist[card->setId].c_str()); + break; + case Constants::RARITY_U: + sprintf(buf,_("%s Uncommon").c_str(),setlist[card->setId].c_str()); + break; + case Constants::RARITY_C: + sprintf(buf,_("%s Common").c_str(),setlist[card->setId].c_str()); + break; + case Constants::RARITY_L: + sprintf(buf,_("%s Land").c_str(),setlist[card->setId].c_str()); + break; + case Constants::RARITY_T: + sprintf(buf,_("%s Token").c_str(),setlist[card->setId].c_str()); + break; + default: + case Constants::RARITY_S: + sprintf(buf,_("%s Special").c_str(),setlist[card->setId].c_str()); + break; + } + + switch(card->data->getColor()) + { + case Constants::MTG_COLOR_BLACK: + case Constants::MTG_COLOR_GREEN: + case Constants::MTG_COLOR_BLUE: + case Constants::MTG_COLOR_LAND: + font->SetColor(ARGB((int)pos.actA,255,255,255)); + font->DrawString(buf, x + (22 - BigWidth / 2)*pos.actZ, pos.actY + (BigHeight / 2 - 30)*pos.actZ); + break; + default: + font->DrawString(buf, x + (22 - BigWidth / 2)*pos.actZ, pos.actY + (BigHeight / 2 - 30)*pos.actZ); + break; //Leave black + } + + } + + font->SetScale(backup_scale); +} + void CardGui::alternateRenderBig(const Pos& pos){ alternateRender(card,pos); renderCountersBig(pos); } +//Renders a big card on screen. Defaults to the "alternate" rendering if no image is found void CardGui::RenderBig(MTGCard* card, const Pos& pos){ JRenderer * renderer = JRenderer::GetInstance(); @@ -361,12 +570,16 @@ void CardGui::RenderBig(MTGCard* card, const Pos& pos){ JQuad * quad = resources.RetrieveCard(card); if (quad){ + if (quad->mHeight < quad->mWidth) { + return tinyCropRender(card, pos, quad); + } quad->SetColor(ARGB((int)pos.actA,255,255,255)); float scale = pos.actZ * 257.f / quad->mHeight; renderer->RenderQuad(quad, x, pos.actY, pos.actT, scale, scale); return; } + //No card found, attempt to render the thumbnail instead (better than nothing, even if it gets super stretched) JQuad * q; if ((q = resources.RetrieveCard(card,CACHE_THUMB))) { diff --git a/projects/mtg/src/CardPrimitive.cpp b/projects/mtg/src/CardPrimitive.cpp index 4137214d5..5bef42ce3 100644 --- a/projects/mtg/src/CardPrimitive.cpp +++ b/projects/mtg/src/CardPrimitive.cpp @@ -67,7 +67,7 @@ const vector& CardPrimitive::formattedText() } while (s.length() > 0) { - std::string::size_type len = neofont ? 24 :30; + std::string::size_type len = neofont ? 24 :33; std::string::size_type cut = s.find_first_of("., \t)", 0); if (cut >= len || cut == string::npos) { diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index 2f834be1c..52cee1b4a 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -1,3 +1,8 @@ +/* + * GameStateDeckViewer.cpp + * Class handling the Deck Editor + */ + #include #include @@ -1210,7 +1215,6 @@ void GameStateDeckViewer::renderCard(int id, float rotation){ if (!card) return; JQuad * quad = NULL; - int showName = 0; int cacheError = CACHE_ERROR_NONE; if(!options[Options::DISABLECARDS].number){ @@ -1221,7 +1225,6 @@ void GameStateDeckViewer::renderCard(int id, float rotation){ quad = resources.RetrieveCard(card); else{ quad = backQuad; - showName = 1; } } } @@ -1229,17 +1232,13 @@ void GameStateDeckViewer::renderCard(int id, float rotation){ int quadAlpha = alpha; if ( !displayed_deck->count(card)) quadAlpha /=2; if (quad){ - showName = 0; - quad->SetColor(ARGB(mAlpha,quadAlpha,quadAlpha,quadAlpha)); - float _scale = scale *(285 / quad->mHeight); - JRenderer::GetInstance()->RenderQuad(quad, x , y , 0.0f,_scale,_scale); - if (showName){ - char buffer[4096]; - sprintf(buffer, "%s", _(card->data->getName()).c_str()); - float scaleBackup = mFont->GetScale(); - mFont->SetScale(scale); - mFont->DrawString(buffer,x - 100*scale ,y - 145*scale); - mFont->SetScale(scaleBackup); + if (quad == backQuad) { + quad->SetColor(ARGB(255,255,255,255)); + float _scale = scale *(285 / quad->mHeight); + JRenderer::GetInstance()->RenderQuad(quad, x , y , 0.0f,_scale,_scale); + } else { + Pos pos = Pos(x, y, scale* 285/250, 0.0, 255); + CardGui::RenderBig(card, pos); } }else{ Pos pos = Pos(x, y, scale* 285/250, 0.0, 255); @@ -1251,11 +1250,10 @@ void GameStateDeckViewer::renderCard(int id, float rotation){ quad->SetColor(ARGB(40,255,255,255)); JRenderer::GetInstance()->RenderQuad(quad,x,y,0,_scale,_scale); } - quadAlpha = 255 - quadAlpha; - if (quadAlpha > 0){ - JRenderer::GetInstance()->FillRect(x - scale* 100 ,y - scale * 142.5,scale* 200,scale*285,ARGB(quadAlpha,0,0,0)); - } - + } + quadAlpha = 255 - quadAlpha; + if (quadAlpha > 0){ + JRenderer::GetInstance()->FillRect(x - scale* 100 ,y - scale * 142.5,scale* 200,scale*285,ARGB(quadAlpha,0,0,0)); } if (last_user_activity < 3){ int fontAlpha = alpha; diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index c647af1a6..f1c39e00d 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -1,3 +1,8 @@ +/* + * GameStateMenu.cpp + * Main Menu and Loading screen + */ + #include #include "../include/config.h" #include "../include/GameStateMenu.h" @@ -11,7 +16,7 @@ #include "../include/utils.h" #include "../include/WFont.h" -static const char* GAME_VERSION = "WTH?! 0.12.1 - by wololo"; +static const char* GAME_VERSION = "WTH?! 0.13.0 - by wololo"; #define DEFAULT_ANGLE_MULTIPLIER 0.4f #define MAX_ANGLE_MULTIPLIER (3*M_PI) diff --git a/projects/mtg/src/GameStateShop.cpp b/projects/mtg/src/GameStateShop.cpp index ef22e46d3..a3d652628 100644 --- a/projects/mtg/src/GameStateShop.cpp +++ b/projects/mtg/src/GameStateShop.cpp @@ -73,6 +73,7 @@ void GameStateShop::Start(){ srcCards = NEW WSrcUnlockedCards(0); srcCards->setElapsed(15); srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T"))); + srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET))); bigSync = 0; shopMenu = NEW WGuiMenu(JGE_BTN_DOWN, JGE_BTN_UP, true, &bigSync); @@ -481,9 +482,11 @@ void GameStateShop::Update(float dt) if (filterMenu->isFinished()){ if (needLoad){ srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T"))); + srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET))); if(!srcCards->Size()){ srcCards->clearFilters(); //Repetition of check at end of filterMenu->Finish(), for the token removal srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterRarity("T"))); + srcCards->addFilter(NEW WCFilterNOT(NEW WCFilterSet(MTGSets::INTERNAL_SET))); } load(); } diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index f878fdf6b..8a999b367 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -255,7 +255,7 @@ void MTGAllCards::init(){ int MTGAllCards::load(const char * config_file, const char * set_name,int autoload){ conf_read_mode = 0; - const int set_id = set_name ? setlist.Add(set_name) : -1; + const int set_id = set_name ? setlist.Add(set_name) : MTGSets::INTERNAL_SET; MTGSetInfo *si = setlist.getInfo(set_id); std::ifstream setFile(config_file); @@ -611,7 +611,7 @@ int MTGDeck::addRandomCards(int howmany, int * setIds, int nbSets, int rarity, c MTGCard * card = database->_(i); int r = card->getRarity(); if (r != Constants::RARITY_T && (rarity == -1 || r==rarity) && // remove tokens - card->setId != -1 && //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally + card->setId != MTGSets::INTERNAL_SET && //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally (!_subtype || card->data->hasSubtype(subtype)) ){ int ok = 0; diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 877197b71..b463b5805 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -829,7 +829,7 @@ MTGMomirRule::MTGMomirRule(int _id, MTGAllCards * _collection):MTGAbility(_id, N MTGCard * card = collection->collection[collection->ids[i]]; if (card->data->isCreature() && (card->getRarity() != Constants::RARITY_T) && //remove tokens - card->setId != -1 //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally + card->setId != MTGSets::INTERNAL_SET //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally ){ int convertedCost = card->data->getManaCost()->getConvertedCost(); if (convertedCost>20) continue; diff --git a/projects/mtg/src/WFilter.cpp b/projects/mtg/src/WFilter.cpp index f3a2c0e77..e5e2020bc 100644 --- a/projects/mtg/src/WFilter.cpp +++ b/projects/mtg/src/WFilter.cpp @@ -178,6 +178,7 @@ string WCFilterLetter::getCode(){ WCFilterSet::WCFilterSet(string arg){ setid = setlist.findSet(arg); } + string WCFilterSet::getCode(){ char buf[256]; sprintf(buf,"set:%s;",setlist[setid].c_str()); diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 5eb739b21..5b4bb3e8d 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -208,9 +208,45 @@ JQuad * WResourceManager::RetrieveCard(MTGCard * card, int style, int submode){ string filename = setlist[card->setId]; filename += "/"; - filename += card->getImageName(); + string filename1 = filename + card->getImageName(); int id = card->getMTGId(); - JQuad * jq = RetrieveQuad(filename,0,0,0,0, "",style,submode|TEXTURE_SUB_5551,id); + + //Aliases. + if(style == RETRIEVE_THUMB){ + submode = submode | TEXTURE_SUB_THUMB; + style = RETRIEVE_NORMAL; + } + + //Hack to allow either ID or card name as a filename for a given card. + // When missing the first attempt (for example [id].jpg), the cache assigns a "404" to the card's image cache, + // Preventing us to try a second time with [name].jpg. + //To bypass this, we first check if the card was ever marked as "null". If not, it means it's the first time we're looking for it + // In that case, we "unmiss" it after trying the [id].jpg, in order to give a chance to the [name.jpg] + bool canUnmiss = false; + { + JQuad * tempQuad = RetrieveQuad(filename1,0,0,0,0, "",RETRIEVE_EXISTING,submode|TEXTURE_SUB_5551,id); + lastError = textureWCache.mError; + if (!tempQuad && lastError != CACHE_ERROR_404){ + canUnmiss = true; + } + } + JQuad * jq = RetrieveQuad(filename1,0,0,0,0, "",style,submode|TEXTURE_SUB_5551,id); + if (!jq) { + if (canUnmiss) { + int mId = id; + //To differentiate between cached thumbnails and the real thing. + if(submode & TEXTURE_SUB_THUMB){ + if (mId < 0) + mId-=THUMBNAILS_OFFSET; + else + mId+=THUMBNAILS_OFFSET; + } + textureWCache.RemoveMiss(mId); + } + filename1 = filename + card->data->getName() + ".jpg"; + jq = RetrieveQuad(filename1,0,0,0,0, "",style,submode|TEXTURE_SUB_5551,id); + int i = 0; //TODO remove debug test; + } lastError = textureWCache.mError; if(jq){ jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2);