308 lines
11 KiB
C#
308 lines
11 KiB
C#
using System.Linq;
|
|
using System;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using System.Collections.Generic;
|
|
using Solitaire.Graphics;
|
|
|
|
namespace Solitaire.Entities {
|
|
public class Card: CardPosition {
|
|
const int SelectedOffset = 3;
|
|
public int DefaultX;
|
|
|
|
public Sprite Sprite {get; private set;}
|
|
public Sprite BackSprite {get; private set;}
|
|
public Sprite FrontSprite {get; private set;}
|
|
public int Value;
|
|
public bool Hidden {get; private set;}
|
|
private bool Selected;
|
|
public CardPosition parent = null;
|
|
|
|
private double lastClicked;
|
|
|
|
public void setSprite() {
|
|
if (Hidden) {
|
|
Sprite = BackSprite;
|
|
} else {
|
|
Sprite = FrontSprite;
|
|
}
|
|
}
|
|
|
|
public Card(int value, bool hidden, Vector2 position, Texture2D spriteSheet): base(position) {
|
|
Offset = 13;
|
|
Value = value;
|
|
Hidden = hidden;
|
|
if (Hidden) {
|
|
Offset = 8;
|
|
}
|
|
|
|
Position = position;
|
|
DefaultX = (int)position.X;
|
|
|
|
Stationary = true;
|
|
|
|
BackSprite = new Sprite(spriteSheet, 320, 192, 32, 48);
|
|
FrontSprite = new Sprite(
|
|
spriteSheet,
|
|
(value % 11) * 32,
|
|
(value / 11) * 48,
|
|
32,
|
|
48
|
|
);
|
|
|
|
setSprite();
|
|
}
|
|
|
|
public void NewPosition(Vector2 position) {
|
|
Position = position;
|
|
DefaultX = (int)position.X;
|
|
}
|
|
|
|
public void Hide() {
|
|
Hidden = true;
|
|
setSprite();
|
|
}
|
|
|
|
public void UnHide() {
|
|
Hidden = false;
|
|
setSprite();
|
|
}
|
|
|
|
public override void Draw(SpriteBatch spriteBatch, GameTime gameTime) {
|
|
Sprite.Draw(spriteBatch, Position);
|
|
}
|
|
|
|
private bool inRectangle(Vector2 point, Rectangle rectangle) {
|
|
return (
|
|
point.X >= rectangle.Left &&
|
|
point.X <= rectangle.Right &&
|
|
point.Y > rectangle.Top &&
|
|
point.Y < rectangle.Bottom
|
|
);
|
|
}
|
|
|
|
public void SetSelected(Vector2 mPosition, bool mHolding) {
|
|
int height = 40;
|
|
if (child != null) {
|
|
height = Offset;
|
|
} else if (Selected) {
|
|
height += SelectedOffset;
|
|
}
|
|
|
|
Rectangle spritePosition = new Rectangle(
|
|
(int)Position.X, (int)Position.Y, 32, height
|
|
);
|
|
if ((!Hidden || child == null) && !mHolding && !Following && inRectangle(mPosition, spritePosition) && !Selected && (child == null || !((Card)child).Selected) && (Offset > 0 || child == null)) {
|
|
Selected = true;
|
|
} else if (!inRectangle(mPosition, spritePosition) && Selected) {
|
|
Selected = false;
|
|
if (child != null) {
|
|
((Card)child).SetSelected(mPosition, mHolding);
|
|
if (((Card)child).Selected) {
|
|
((Card)child).SetPosition(mPosition);
|
|
}
|
|
}
|
|
if (parent != null) {
|
|
if (parent is Card) {
|
|
((Card)parent).SetSelected(mPosition, mHolding);
|
|
if (((Card)parent).Selected) {
|
|
((Card)parent).SetPosition(mPosition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetPosition(Vector2 mPosition) {
|
|
int X;
|
|
int Y;
|
|
|
|
if (Following) {
|
|
X = (int)mPosition.X - 16;
|
|
Y = (int)mPosition.Y - 16;
|
|
} else {
|
|
X = (int)parent.Position.X;
|
|
Y = (int)parent.Position.Y + parent.Offset;
|
|
}
|
|
|
|
if (Selected && !Following) {
|
|
Y -= SelectedOffset;
|
|
}
|
|
|
|
Position = new Vector2(X, Y);
|
|
|
|
}
|
|
|
|
public void SetStationary(bool stationary) {
|
|
Stationary = stationary;
|
|
if (child != null) {
|
|
((Card)child).SetStationary(stationary);
|
|
}
|
|
}
|
|
|
|
private bool IsCloser(CardPosition other, CardPosition closest) {
|
|
return (
|
|
other.Stationary &&
|
|
other.child == null &&
|
|
(
|
|
closest == null ||
|
|
Vector2.Distance(closest.Position, Position) > Vector2.Distance(other.Position, Position)
|
|
) &&
|
|
ValidPlacement(other)
|
|
);
|
|
}
|
|
|
|
private bool ValidPlacement(CardPosition other) {
|
|
return (
|
|
other == parent ||
|
|
(
|
|
!(other is Card) &&
|
|
(
|
|
(
|
|
!other.TopPile &&
|
|
(
|
|
(
|
|
Deck && other.Deck
|
|
) ||
|
|
(
|
|
!other.Deck &&
|
|
Value % 13 == 12
|
|
)
|
|
)
|
|
) ||
|
|
(
|
|
other.TopPile &&
|
|
Value % 13 == 0
|
|
)
|
|
)
|
|
) ||
|
|
(
|
|
other is Card &&
|
|
(
|
|
(
|
|
!other.Deck &&
|
|
(
|
|
(
|
|
other.TopPile &&
|
|
Value / 13 == ((Card)other).Value / 13 &&
|
|
Value - 1 == ((Card)other).Value
|
|
) ||
|
|
(
|
|
(Value % 13 + 1 == ((Card)other).Value % 13) &&
|
|
((Value / 13) % 2 != (((Card)other).Value / 13) % 2)
|
|
)
|
|
)
|
|
) ||
|
|
(
|
|
Deck && other.Deck && !((Card)other).Hidden
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
public override void Update(GameTime gameTime, Vector2 mPosition, bool mReleased, bool mHolding, List<IGameEntity> entities) {
|
|
SetSelected(mPosition, mHolding);
|
|
|
|
if (parent != null && !Following) {
|
|
DrawOrder = parent.DrawOrder + 1;
|
|
} else if (!Following) {
|
|
DrawOrder = 1;
|
|
}
|
|
|
|
if (Selected && mReleased && !Following) {
|
|
if (!Hidden) {
|
|
lastClicked = gameTime.TotalGameTime.TotalSeconds;
|
|
Following = true;
|
|
SetStationary(false);
|
|
Selected = false;
|
|
DrawOrder = 1000;
|
|
} else {
|
|
UnHide();
|
|
if (Deck) {
|
|
parent.child = null;
|
|
Selected = false;
|
|
SolitaireGame.logic.DeckRevealed.Last().child = this;
|
|
parent = SolitaireGame.logic.DeckRevealed.Last();
|
|
SolitaireGame.logic.DeckRevealed.Add(this);
|
|
SolitaireGame.logic.DeckHidden.Remove(this);
|
|
parent.Offset = 0;
|
|
}
|
|
}
|
|
} else if (Following && mReleased) {
|
|
CardPosition closest = null;
|
|
CardPosition oldPosition = parent;
|
|
|
|
parent.child = null;
|
|
|
|
foreach (IGameEntity entity in entities) {
|
|
if (entity is CardPosition) {
|
|
if (IsCloser((CardPosition)entity, closest)) {
|
|
closest = (CardPosition)entity;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (closest != null && Vector2.Distance(closest.Position, Position) < 50) {
|
|
if (ValidPlacement(closest)) {
|
|
Following = false;
|
|
SetStationary(true);
|
|
closest.child = this;
|
|
parent = closest;
|
|
if (parent is Card && !((Card)parent).Hidden){
|
|
parent.Offset = 13;
|
|
}
|
|
if (parent.TopPile) {
|
|
TopPile = true;
|
|
parent.Offset = 0;
|
|
} else {
|
|
TopPile = false;
|
|
}
|
|
|
|
if (Deck && !closest.Deck) {
|
|
Deck = false;
|
|
SolitaireGame.logic.DeckRevealed.Remove(this);
|
|
}
|
|
|
|
if (Deck) {
|
|
parent.Offset = 0;
|
|
}
|
|
}
|
|
} else {
|
|
Following = false;
|
|
SetStationary(true);
|
|
oldPosition.child = this;
|
|
parent = oldPosition;
|
|
}
|
|
|
|
if (gameTime.TotalGameTime.TotalSeconds - lastClicked < 0.3 && parent == oldPosition) {
|
|
foreach (IGameEntity entity in SolitaireGame.entities) {
|
|
if (entity is CardPosition && ((CardPosition)entity).TopPile && ((CardPosition)entity).child == null) {
|
|
if (
|
|
(entity is Card && ((Card)entity).Value % 13 == Value % 13 - 1 && ((Card)entity).Value / 13 == Value / 13) ||
|
|
(!(entity is Card) && Value % 13 == 0)
|
|
) {
|
|
parent.child = null;
|
|
((CardPosition)entity).child = this;
|
|
parent = ((CardPosition)entity);
|
|
TopPile = true;
|
|
parent.Offset = 0;
|
|
|
|
if (Deck) {
|
|
Deck = false;
|
|
SolitaireGame.logic.DeckRevealed.Remove(this);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (Following && (mPosition.X < 0 || mPosition.X > SolitaireGame.gameWidth || mPosition.Y < 0 || mPosition.Y > SolitaireGame.gameHeight)) {
|
|
Following = false;
|
|
SetStationary(true);
|
|
}
|
|
|
|
SetPosition(mPosition);
|
|
}
|
|
}
|
|
} |