Skip to content

Updated display of Maximum Summon#300

Open
Yoshi80 wants to merge 27 commits into
edo9300:masterfrom
Yoshi80:maximum-display
Open

Updated display of Maximum Summon#300
Yoshi80 wants to merge 27 commits into
edo9300:masterfrom
Yoshi80:maximum-display

Conversation

@Yoshi80

@Yoshi80 Yoshi80 commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

The list of features included in this PR is the following:

  • Maximum Summoned monsters on the field now display as a single monster.
  • Change the card hint when Maximum Summoning to display all 3 pieces at once.
  • Maximum Summoned monsters on the field now only show one Level and don't show their DEF.
  • Selecting a Maximum Summoned monster on the field can be done by selecting either of its pieces.
  • A monster whose only Special Summon procedure is a Maximum Summon will display "Maximum Summon".
  • When selecting zones to place monsters on the field, if only one zone is a valid choice, that zone will be chosen automatically.

Comment thread gframe/drawing.cpp Outdated
Comment on lines +185 to +203
if(mcenter) {
driver->setMaterial(matManager.mSelField);
int seq = mcenter->sequence;
if(seq > 0) {
Materials::QuadVertex side;
for(int i = 0; i < 4; ++i) side[i] = matManager.vFieldMzone[dField.hovered_controler][seq - 1][i];
side[0].Pos = side[0].Pos.getInterpolated(side[1].Pos, 0.5f);
side[2].Pos = side[2].Pos.getInterpolated(side[3].Pos, 0.5f);
driver->drawVertexPrimitiveList(side, 4, matManager.iRectangle, 2);
}
driver->drawVertexPrimitiveList(matManager.vFieldMzone[dField.hovered_controler][seq], 4, matManager.iRectangle, 2);
if(seq < 4) {
Materials::QuadVertex side;
for(int i = 0; i < 4; ++i) side[i] = matManager.vFieldMzone[dField.hovered_controler][seq + 1][i];
side[1].Pos = side[1].Pos.getInterpolated(side[0].Pos, 0.5f);
side[3].Pos = side[3].Pos.getInterpolated(side[2].Pos, 0.5f);
driver->drawVertexPrimitiveList(side, 4, matManager.iRectangle, 2);
}
return;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here all the drawing should be doable with a single vertex drawing (since you're drawing 3 rectangles that in the end are forming a single rect)

Comment thread gframe/drawing.cpp Outdated
Comment on lines +993 to +995
for(size_t i = 0; i < rects.size() - 1; ++i) {
rects[i].LowerRightCorner.X = rects[i + 1].UpperLeftCorner.X;
} } else {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code is not properly indented

Comment thread gframe/drawing.cpp Outdated
Comment on lines +998 to +1002
for(size_t i = 0; i < codes.size(); ++i) {
auto cardtxt = imageManager.GetTextureCard(codes[i], imgType::ART);
auto cardrect = irr::core::rect<irr::s32>(irr::core::vector2di(0, 0), irr::core::dimension2di(cardtxt->getOriginalSize()));
driver->draw2DImage(cardtxt, rects[i], cardrect, 0, matManager.c2d, true);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is more of a note for myself that in case this could be made a single call to draw2DImageBatch

Comment thread gframe/client_field.cpp Outdated
Comment on lines +834 to +843
if(pcard->IsMaximumSide()) {
float offset = 0.4f;
if(controler == 0) {
if(sequence == 1) t->X += offset;
else if(sequence == 3) t->X -= offset;
} else {
if(sequence == 1) t->X -= offset;
else if(sequence == 3) t->X += offset;
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently IsMaximumSide doesn't enforce a maximum side piece to be sequence 1/3. In case either that has to be checked there, or this piece of code needs to be made sequence agnostic and check if the card is the left or right piece and act accordingly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure how to proceed here because even though the client doesn't enforce the sequence of the maximum side pieces, it is handled script-wise in the proc_maximum. And because of this, a monster in Maximum Mode will always have its side pieces in the same sequence.

Comment thread gframe/drawing.cpp Outdated
ClientCard* mcenter = nullptr;
for(int p = 0; p < 2; ++p) {
for(auto pcard : dField.mzone[p]) {
if(pcard && pcard->code == showcardcode && pcard->IsMaximumCenter()) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't technically right, since both players could have the same card on the field, and for some reasons they might have different side pieces, leading to wrong popup image being displayed. But this is due to a limitation of how the client does things atm, so it's something to be addressed at a later time in case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this part. In all my testing, the correct popup image has always been displayed correctly, even with different side pieces. Could you give me an example of this ?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • player 0 has a maximum monster in play with a center piece x and 2 side pieces
  • player 1 summons a maximum with same center piece but another pair of side pieces
  • this logic would show player 0's maximum pieces

Comment thread gframe/event_handler.cpp Outdated
Comment on lines +23 to +27
#include <unordered_map>
#include <IrrlichtDevice.h>
#include <ISceneManager.h>
#include <IFileSystem.h>
#include <IReadFile.h>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftover headers

Comment thread gframe/event_handler.cpp Outdated
else clicked_card = 0;
if(clicked_card && clicked_card->IsMaximumSide()) {
ClientCard* center = clicked_card->GetMaximumCenter();
if(center && center->is_selectable)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking for is_selectable will prevent the side pieces to be used for general actions like attacking or using effects. Is it intentional? i don't remember atm if side pieces can have individual effects requiring that piece specifically to be selected to be activated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional. Side pieces are not considered monsters on the field so they cannot attack or use effects, or do anything at all. You have to think that when in Maximum Mode, it become essentially just the center piece, who gains the effects of the side pieces.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then removing the is_selectable check should be the way to go, since it'll consider clicking a side piece as clicking the center piece under any circumstance (currently it won't let you declare an attack by clicking on the side piece for example)

Comment thread gframe/client_card.cpp Outdated
Comment on lines +128 to +164
ClientCard* ClientCard::GetMaximumCenter() {
if(IsMaximumCenter())
return this;
if(!(type & TYPE_MAXIMUM) || location != LOCATION_MZONE || !(position & POS_FACEUP))
return nullptr;
const auto& zone = mainGame->dField.mzone[controler];
if(sequence > 0 && sequence - 1 < zone.size()) {
ClientCard* neighbor = zone[sequence - 1];
if(neighbor && neighbor->IsMaximumCenter())
return neighbor;
}
if(sequence + 1 < zone.size()) {
ClientCard* neighbor = zone[sequence + 1];
if(neighbor && neighbor->IsMaximumCenter())
return neighbor;
}
return nullptr;
}
bool ClientCard::IsMaximumCenter() const {
return (status & STATUS_MAXIMUM_CENTER) != 0;
}
bool ClientCard::IsMaximumSide() const {
if(!(type & TYPE_MAXIMUM) || location != LOCATION_MZONE || !(position & POS_FACEUP))
return false;
const auto& zone = mainGame->dField.mzone[controler];
if(sequence > 0 && sequence - 1 < zone.size()) {
ClientCard* neighbor = zone[sequence - 1];
if(neighbor && neighbor->IsMaximumCenter())
return true;
}
if(sequence + 1 < zone.size()) {
ClientCard* neighbor = zone[sequence + 1];
if(neighbor && neighbor->IsMaximumCenter())
return true;
}
return false;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some extra sanity checks might be added to these functions, like checking that a center piece is a center only if it has 2 sides, and all the 3 pieces are in the main monster zones. In case any of these conditions fail, then none of them should be considered part of a maximum monster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants