Files
PTS3-SERVEUR/src/game/Joueur.java
T
2021-01-09 14:39:03 +01:00

577 lines
14 KiB
Java

package game;
import java.io.IOException;
import java.util.Iterator;
import game.cards.Card;
import game.cards.CardRegistery;
import game.cards.SpecialCard.IAntiPlayer;
import game.cards.SpecialCard.ICanDoge;
import game.cards.SpecialCard.IInvisible;
import game.cards.SpecialCard.ILifeSteal;
import game.cards.SpecialCard.IPlayerFocused;
import game.cards.SpecialCard.IShortRange;
import game.cards.SpecialCard.IToxic;
import game.deck.Deck;
import game.deck.DeckRegistery;
public class Joueur {
private ComsJoueur coms;
private Deck deck;
private Hand hand;
private Board board;
private int pV;
// la quantité maximum de mana elle augment de 1 par tours
private int currentMana = 0;
// la mana actuele du joueur
private int mana;
public Joueur(ComsJoueur connectionJoueur) {
coms = connectionJoueur;
pV = 20;
this.board = new Board();
}
/**
* cette fonction permet d'obtenir le deck du joueur et de préparer la main
* /!\\ l'appele de cette fonction doit être protegé par la verification de la tille du deck
* @throws IOException
*/
public void requestDataEarlyGameData() throws IOException {
coms.send(Command.GET_DECK);
String deckname = coms.recieve();
deck = DeckRegistery.get(deckname);
deck.shuffle();
hand = new Hand(deck);
coms.send(DeckSerializer.serializeDeck(deck));
draw(5);
coms.send(Command.SET_HP);
coms.send(pV);
coms.send(Command.SET_ENEMY_HP);
coms.send(pV);
}
/**
* cette fonction permet de pioche une quantité donné
* /!\\ l'appele de cette fonction doit être protegé par la verification de la tille du deck
* @param amount la quantié
* @throws IOException
*/
public void draw(int amount) throws IOException {
coms.send(Command.DRAW);
coms.send(amount);
hand.draw(amount);
}
/**
* affiche sur l'ecran que c'est le tours de l'adversaire
*
* @throws IOException
*/
public void debutTourEnemie() throws IOException {
coms.send(Command.ENEMYTURN);
}
/**
* affiche un menu de victoire
*
* @throws IOException
*/
public void win() throws IOException {
coms.send(Command.WIN);
}
/**
* affiche un menu de defaite
*
* @throws IOException
*/
public void lose() throws IOException {
coms.send(Command.LOSE);
}
/**
* cette commande doit être utilisé a chaque début de tour elle permet
* d'augmenter la mana du joueur
*
* @throws IOException
*/
public void prepMana() throws IOException {
// on prepare la mana
if (currentMana < 10)
currentMana++;
mana = currentMana;
coms.send(Command.SETMANA);
coms.send(mana);
}
/**
* premiére phase de jeu avant d'attacker
*
* @param adversaire
* @param board
* @throws IOException
*/
public void mainPhase1(Joueur adversaire) throws IOException {
boolean phaseActive = true;
// on retire le time out sur l'adversaire car sa peut causer des
// désyncronisatoin et des crash
adversaire.getComs().getSocket().setSoTimeout(Integer.MAX_VALUE);
// debut de l'écoude des action client
int alive = 0;
while (phaseActive) {
coms.getSocket().setSoTimeout(500);
String command = coms.recieve();
coms.getSocket().setSoTimeout(Integer.MAX_VALUE);
if (command != null && !command.equals("time out")) {
alive = 0;
System.out.println("GOT COMMAND :" + command);
switch (command) {
case Command.PING:
coms.send(Command.PONG);
break;
case Command.PASS_TURN:
phaseActive = false;
break;
case Command.PUT_CARD:
System.out.println("entering put card");
putCard(adversaire, board);
break;
default:
System.err.println("unknown command " + command);
}
} else {
alive++;
// 3000xalive =300s = 5minutes
// si au bout de 5 minute le client ne repond pas on envoie une erreur
if (alive > 300000) {
throw new IOException("dead client");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
// cette mothode est utilisé l'orse qu'un joueur utilise Command.PLACECARD
// elle verifie si le joueur peut la jouer et refuse ou confirme en fonction
private void putCard(Joueur adversaire, Board board) throws IOException {
String info = coms.recieve();
// si ce n'est pas un nombre
if (!isInt(info)) {
// alors on affiche l'inforamtion si la sortie d'erreur
System.err.println(info);
} else {
// on recupére la carte
int cardId = Integer.parseInt(info);
Class<? extends Card> cardClass = CardRegistery.get(cardId);
System.out.println("searching :"+cardClass.getSimpleName());
int zone = Integer.parseInt(coms.recieve());
Card handCard = hand.contains(cardClass);
// si la carte n'est pas trouve ou si elle coute trop cher
if (handCard == null || mana < handCard.getCost()) {
// on refuse le placement
System.out.println("no mana or no card printing hand");
hand.print();
System.out.println("hand status :");
System.out.println(handCard);
System.out.println("mana :" + mana);
System.out.println("cost :" + handCard.getCost());
coms.send(Command.NOK);
} else {
if (board.isZoneAvaliable(zone)) {
hand.remove(handCard);
board.setCard(zone, handCard);
adversaire.enemyPlay(cardId, zone);
coms.send(Command.OK);
coms.send(Command.SETMANA);
mana -= handCard.getCost();
coms.send(mana);
handCard.onCardPlaced(board);
refreshAllCard(adversaire);
} else {
System.out.println("the zone is not avaliable");
coms.send(Command.NOK);
}
}
}
}
private boolean isInt(String info) {
return info.matches("-?\\d+");
}
/**
* cette fonctoin est appelé affin de placer une carte sur le plateur énemie
*
* @param cardId
* @param zone
* @throws IOException
*/
private void enemyPlay(int cardId, int zone) throws IOException {
coms.send(Command.PUT_ENEMY_CARD);
coms.send(cardId);
coms.send(zone);
}
/**
* cette methode a pour but d'executé les evenement de fin de trous des cartes
*/
public void endPhase() {
Iterator<Card> it = board.getIterator();
while(it.hasNext())
{
Card c = it.next();
if (c != null) {
c.resetAttack();
}
}
}
public ComsJoueur getComs() {
return coms;
}
public void setPV(int pV) {
this.pV = pV;
}
public boolean isDead() {
return pV == 0;
}
public boolean isAlive() {
return !isDead();
}
/**
* envoie le message donné qui aparaitera alors comme une toast
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
coms.send(Command.POPUP);
coms.send(message);
}
/**
* affiche le debut de tours
*
* @throws IOException
*/
public void yourturn() throws IOException {
// on affiche le debut de tour
coms.send(Command.YOURTURN);
}
public boolean isHandFull() {
return hand.isFull();
}
/**
* retire le nombre de carte donné du deck
*
* @param nbcard nombre de carte a supprimé
* @throws IOException
*/
public void meule(int nbcard) throws IOException {
coms.send(Command.MEULE);
coms.send(nbcard);
deck.draw(1);
}
public void battlePhase(Joueur adversaire) throws IOException {
coms.send(Command.BATTLE);
boolean phaseActive = true;
adversaire.getComs().getSocket().setSoTimeout(Integer.MAX_VALUE);
// debut de l'écoude des action client
while (phaseActive) {
coms.getSocket().setSoTimeout(500);
String command = coms.recieve();
coms.getSocket().setSoTimeout(Integer.MAX_VALUE);
if (command != null && !command.equals("time out")) {
System.out.println("GOT COMMAND :" + command);
switch (command) {
case Command.PING:
coms.send(Command.PONG);
break;
case Command.PASS_TURN:
phaseActive = false;
break;
case Command.ATTACK:
// numero de la zone de la carte attaquante
String carteAttaquante = coms.recieve();
// numero de la zone de la carte ciblé
String carteCible = coms.recieve();
if (!isInt(carteAttaquante) || !isInt(carteCible))
throw new RuntimeException("non number zone recived in attack phase");
Card attackingCard = board.getCardInZone(Integer.parseInt(carteAttaquante));
if (attackingCard == null) {
throw new RuntimeException("invalid attack");
} else {
if (carteCible.contains("100")) {
if(!attackingCard.hasAlreadyAttacked())
{
boolean isadvDead = handleAttackAgainstPlayer(attackingCard, adversaire);
if(isadvDead)
{
phaseActive = false;
}
attackingCard.hasAttacked();
}
} else {
Card attackedCard = adversaire.getBoard().getCardInZone(Integer.parseInt(carteCible));
if (!attackingCard.hasAlreadyAttacked() && !(attackedCard instanceof IInvisible) && !(attackingCard instanceof IPlayerFocused)) {
handleAttackAgainstCard(carteAttaquante, carteCible, adversaire);
attackingCard.hasAttacked();
}
}
}
break;
default:
System.err.println("unknown command " + command);
}
}
}
}
private boolean handleAttackAgainstPlayer(Card attackingCard, Joueur adversaire) throws IOException {
int damage = attackingCard.getAttack();
if(attackingCard instanceof IAntiPlayer)
{
damage *= 2;
}
if(attackingCard instanceof IShortRange)
{
damage = 0;
}
boolean result = adversaire.takeDamage(damage);
if(!result)
{
adversaire.updateHp(this);
return false;
}
return true;
}
public void updateHp(Joueur adversaire) throws IOException {
coms.send(Command.SET_HP);
coms.send(pV);
adversaire.coms.send(Command.SET_ENEMY_HP);
adversaire.coms.send(pV);
}
private void handleAttackAgainstCard(String carteAttaquante, String carteCible, Joueur adversaire) throws IOException {
Card attackedCard = adversaire.getBoard().getCardInZone(Integer.parseInt(carteCible));
Card attackingCard = board.getCardInZone(Integer.parseInt(carteAttaquante));
if (attackedCard == null) {
throw new RuntimeException(
"error invalid carteCible:" + carteCible + " carteAttaquante : " + attackingCard);
}
boolean isDestroyed = attackedCard.takeDamage(attackingCard.getAttack());
if(attackingCard instanceof ILifeSteal)
{
attackingCard.heal(attackingCard.getAttack());
updateCardHp(attackingCard, this);
}
if (isDestroyed || attackingCard instanceof IToxic) {
adversaire.destroyCard(carteCible,this);
}else {
adversaire.updateCardHp(attackedCard, this);
//cette partie est le fightback C.A.D quand tu attaque une carte si elle survit elle te frape a son tour
if(attackedCard.getAttack() > 0 && !(attackingCard instanceof ICanDoge))
{
isDestroyed = attackingCard.takeDamage(attackedCard.getAttack());
if(isDestroyed)
{
// on suprime la carte du terrain
board.setCard(Integer.parseInt(carteAttaquante), null);
// demande a l'adversaire de retirer la carte de son terrain
adversaire.getComs().send(Command.DESTROY_ADV_CARD);
adversaire.getComs().send(carteAttaquante);
// retire la carte au terrain adverse
this.getComs().send(Command.DESTROY_CARD);
this.getComs().send(carteAttaquante);
// appelle les effet de quand la carte est détruite
// NOTE : non implémenter dans les cartes individuelles par manque de temps
attackingCard.onCardDestroyed();
}else {
adversaire.updateCardHp(attackingCard, this);
}
}
}
}
private void destroyCard(String carteCible,Joueur adversaire) throws IOException
{
Card attackedCard = getBoard().getCardInZone(Integer.parseInt(carteCible));
board.setCard(Integer.parseInt(carteCible), null);
// demande a l'adversaire de retirer la carte de son terrain
getComs().send(Command.DESTROY_CARD);
getComs().send(carteCible);
// retire la carte au terrain adverse
adversaire.getComs().send(Command.DESTROY_ADV_CARD);
adversaire.getComs().send(carteCible);
// appelle les effet de quand la carte est détruite
// NOTE : non implémenter dans les cartes individuelles par manque de temps
attackedCard.onCardDestroyed();
}
/**
* met a jorus les hp d'une carte tout ce passe du poin de vue du joueur
* @param cardToUpDate
* @param adversaire
* @throws IOException
*/
private void updateCardHp(Card cardToUpDate,Joueur adversaire) throws IOException
{
int zone = board.getZoneOf(cardToUpDate);
if(zone == -1)return;
adversaire.getComs().send(Command.SET_ADV_CARD_HP);
adversaire.getComs().send(zone+"");
adversaire.getComs().send(cardToUpDate.getHealth());
this.getComs().send(Command.SET_CARD_HP);
this.getComs().send(zone+"");
this.getComs().send(cardToUpDate.getHealth());
}
/**
* met a jorus les dmg d'une carte tout ce passe du poin de vue du joueur
* @param cardToUpDate
* @param adversaire
* @throws IOException
*/
private void updateCardAtk(Card cardToUpDate,Joueur adversaire) throws IOException
{
int zone = board.getZoneOf(cardToUpDate);
if(zone == -1)return;
adversaire.getComs().send(Command.SET_ADV_CARD_ATK);
adversaire.getComs().send(zone+"");
adversaire.getComs().send(cardToUpDate.getAttack());
this.getComs().send(Command.SET_CARD_ATK);
this.getComs().send(zone+"");
this.getComs().send(cardToUpDate.getAttack());
}
private Board getBoard() {
return board;
}
/**
* inflige des degats au joueur
* @param amount
* @return true si les pv du joueur on attein zero
*/
public boolean takeDamage(int amount)
{
pV -= amount;
pV = pV > 0 ? pV : 0;
return pV == 0;
}
public void onTurnStart(Joueur adversaire) throws IOException {
int index = 0;
Iterator<Card> it = board.getIterator();
while(it.hasNext())
{
Card c = it.next();
if(c != null)
{
c.onTurnStart();
if(!(c.getHealth() == 0))
{
updateCardHp(c, adversaire);
updateCardAtk(c, adversaire);
}else {
destroyCard(index+"", adversaire);
}
}
index++;
}
}
public void refreshAllCard(Joueur adversaire) throws IOException {
int index = 0;
Iterator<Card> it = board.getIterator();
while(it.hasNext())
{
Card c = it.next();
if(c != null)
{
if(!(c.getHealth() == 0))
{
updateCardHp(c, adversaire);
updateCardAtk(c, adversaire);
}else {
destroyCard(index+"", adversaire);
}
}
index++;
}
}
public Deck getDeck() {
return deck;
}
}