+
+## ***702.3 Defender*** 🧱
+
+### **Descrizione** :mag:
+
+- `.a` _Defender is a static ability._
+- `.b` _A creature with defender can't attack._
+- `.c` _Multiple instances of defender on the same creature are redundant._
+
+### **Implementazione :computer:**
+
+#### 1. Trovare `Defender` nei mazzi
+
+- Quando il **gioco** è nella fase `STARTING_STAGE`,
+- prendiamo tutti i player in gioco e per ognuno prendiamo tutte le **abilità ** di ogni carta che hanno nel mazzo,
+- controlliamo quale di queste ha nell'`abilityText` la parola `Defender`
+- Una volta effettuato questo controllo andiamo ad **impostare**, per ogni carta, le proprietà `keyword_ability` e `static_ability` a `true` della rispettiva abilità .
+
+
+``` java
+rule "702.3a"
+/*
+ 9th January 2023
+ 702.3a. Defender is a static ability.
+*/
+dialect "mvel"
+no-loop true
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck, $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && abilityText.startsWith("Defender")) from $la
+ then
+ System.out.println("702.3a -> Trovata Defender");
+ $a.setKeyword_ability(true);
+ $a.setStatic_ability(true);
+ update($p)
+end
+```
+
+#### 2. Attivazione di `Defender`
+
+La regola `508.1a choice`, responsabile dell'individuazione **dei possibili attaccanti**, è stata modificata come segue:
+
+- se all'interno del campo di battaglia viene trovata una carta con abilità `Defender` questa non **attaccherà ** e setteremo il flag `nodefender=false`, nel caso in cui la carta non avesse l'abilità `Defender` potrà attaccare come in un normale combattimento e avremmo che il flag `nodefender` resterà settato a `true`.
+
+
+``` java
+rule "508.1a choice"
+/*
+--- November 19, 2021 ---
+508.1a. The active player chooses which creatures that he or she controls,
+if any, will attack. The chosen creatures must be untapped, and each one must
+either have haste or have been controlled by the active player continuously since
+the turn began.*/
+agenda-group "general"
+dialect "mvel"
+salience 50
+no-loop true
+when
+ $g:Game(stage == Game.GAME_STAGE, $ac : attackingPlayer, stepTimeFrame == Game.BEGIN_TIME_FRAME)
+ eval($g.currentStep.getObject().name == "declare attackers")
+ eval($g.stepDeclareAttackers.getObject() == "508.1a")
+ $p: Player($id : id) from $ac.object
+then
+ System.out.println("508.1a choice --> Il giocatore sta scegliendo gli attaccanti");
+ MakeChoice choice = new MakeChoice();
+ choice.idChoice = 50811;//ATTENZIONE
+ choice.choiceText = "Choose which creature will attack";
+ boolean found = false;
+ choice.addOption(-1, "No attack");
+
+ /*
+ Rule 702.3b. A creature with defender can't attack.
+ */
+ for(Permanent permanent : $g.battleField) {
+ if(permanent.idController == $id && !permanent.getStatus().isTapped() && !permanent.summoningSickness && permanent.cardType[0].contains("creature")){
+ boolean nodefender = true;
+
+ // Defender check of the selected permanent.
+ if (permanent.checkKeywordAbility("Defender")){
+ System.out.println("702.3b -> Card has Defender, can't attack !");
+ nodefender = false;
+ }
+
+ if (nodefender){
+ choice.addOption(permanent.magicTargetId, permanent.getNameAsString());
+ found = true;
+ }
+ }
+ }
+ if(found){
+ GameEngine.sendToNode(choice, Game.CHOICE, Game.MULTIPLE_CHOICE, $id);
+ } else {
+ GameEngine.sendToNode("You have not creature to attack.");
+ System.out.println("508.1a --> Il giocatore non ha creature per attaccare");
+ $g.stepDeclareAttackers.next();
+ }
+ update($g);
+end
+```
+
+
+
+## ***702.4 Double Strike*** :bowling: :bowling:
+
+### **Descrizione** :mag:
+- `.a` _Double strike is a static ability that modifies the rules for the combat damage step._ (See rule [510](https://yawgatog.com/resources/magic-rules/#R510), "Combat Damage Step.")
+- `.b` _If at least one attacking or blocking creature has first strike (see rule [702.7](https://yawgatog.com/resources/magic-rules/#R7027)) or double strike as the combat damage step begins, the only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have double strike. After that step, the phase proceeds to the end of combat step._
+- `.c` _Removing double strike from a creature during the first combat damage step will stop it from assigning combat damage in the second combat damage step._
+- `.d` _Giving double strike to a creature with first strike after it has already dealt combat damage in the first combat damage step will allow the creature to assign combat damage in the second combat damage step._
+- `.e` _Multiple instances of double strike on the same creature are redundant._
+
+### **Implementazione :computer:**
+#### 1. Trovare `Double Strike` nei mazzi
+
+- Quando il **gioco** è nella fase `STARTING_STAGE`,
+- prendiamo tutti i player in gioco e per ognuno prendiamo tutte le **abilità ** di ogni carta che hanno nel mazzo,
+- controlliamo quale di queste ha nel `keyword_text` la parola `Double Strike`.
+- Una volta effettuato questo controllo andiamo ad **impostare**, per ogni carta, le proprietà `keyword_ability` e `static_ability` a `true` della rispettiva abilità .
+``` java
+rule "702.4a"
+/**
+ @date 2022/2023
+ @author Tommaso Romani, Nicolò Posta
+**/
+/*Double Strike is a static ability.*/
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ abilityText.toLowerCase().contains("double strike")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setKeyword_ability(true);
+ $a.setKeyword_text("double strike");
+ System.out.println("702.4a -> Trovato Double Strike: " + $c.getName());
+ update($p)
+end
+```
+
+
+
+## ***702.7 First Strike*** :bowling:
+
+### **Descrizione** :mag:
+- `.a` _First strike is a static ability that modifies the rules for the combat damage step. (See rule [510](https://yawgatog.com/resources/magic-rules/#R510), "Combat Damage Step.")_
+- `.b` _If at least one attacking or blocking creature has first strike or double strike (See rule [702.4](https://yawgatog.com/resources/magic-rules/#R7024) as the combat damage step begins, the only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have double strike. After that step, the phase proceeds to the end of combat step._
+- `.c` _Giving first strike to a creature without it after combat damage has already been dealt in the first combat damage step won't preclude that creature from assigning combat damage in the second combat damage step. Removing first strike from a creature after it has already dealt combat damage in the first combat damage step won't allow it to also assign combat damage in the second combat damage step (unless the creature has double strike)._
+- `.d` _Multiple instances of first strike on the same creature are redundant._
+
+### **Implementazione :computer:**
+#### 1. Trovare `First Strike` nei mazzi
+
+- Quando il **gioco** è nella fase `STARTING_STAGE`,
+- prendiamo tutti i player in gioco e per ognuno prendiamo tutte le **abilità ** di ogni carta che hanno nel mazzo,
+- controlliamo quale di queste ha nel `keyword_text` la parola `First Strike`.
+- Una volta effettuato questo controllo andiamo ad **impostare**, per ogni carta, le proprietà `keyword_ability` e `static_ability` a `true` della rispettiva abilità .
+``` java
+rule "702.7a"
+/**
+ @date 2022/2023
+ @author Tommaso Romani, Nicolò Posta
+**/
+/*First Strike is a static ability.*/
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ abilityText.toLowerCase().contains("first strike")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setKeyword_ability(true);
+ $a.setKeyword_text("first strike");
+ System.out.println("702.7a -> Trovato First Strike: " + $c.getName());
+ update($p)
+end
+```
+
+
+## ***510.4 Gestione Turno Bonus*** :bowling: :bowling: :bowling:
+
+### ***Descrizione***
+
+- _If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have double strike. After that step, the phase proceeds to the end of combat step_
+
+
+### ***Implementazione***
+#### 1. Controllare la presenza di creature con ***First/Double Strike*** tra gli attaccanti o i difensori.
+- Se sono presenti creature con `First` o `Double Strike` allora viene aggiunto un `combat damage` step bonus.
+``` java
+rule "506.1 part 3"
+/* Tommaso Romani Nicolò Posta
+There are two combat damage steps if any attacking or blocking creature has first strike
+(see rule 702.7) or double strike (see rule 702.4).*/
+dialect "mvel"
+salience 50
+no-loop true
+agenda-group "general"
+when
+ $g:Game(stage == Game.GAME_STAGE, $bf: battleField, $ph: currentPhase.getObject())
+ eval($g.currentPhase.getObject().name == "combat")
+ eval($ph.size() <= 5)
+ //TODO: mettere che siano tra gli attaccanti o i bloccanti
+ exists (Permanent(
+ (checkKeywordAbility("Double strike") || checkKeywordAbility("First strike"))
+ ) from $bf)
+then
+ System.out.println("506.1 part 3 -> Aggiunto combat damage per First/Double strike");
+
+ $ph.remove($ph.size()-1);
+ $ph.remove($ph.size()-1);
+ $ph.add(new Step("combat damage",true));
+ $ph.add(new Step("combat damage",false));
+ $ph.add(new Step("end of combat",false));
+
+ update($g)
+
+end
+```
+#### ***2. Controllo se ci sono creature con Fist o Double strike tra gli attaccanti o i difensori quandi ci si trova nel combat damage step***
+- Se ci si trova nel `Combat Damage Step` aggiuntivo allora mi salvo tutte le creature in una lista ausiliaria.
+- Pulisco la lista degli attacker e ci riaggiungo le creature con `First/Double Strike`.
+- Aggiorno la variabile booleana `firstStrikeAttacking` a `true` per informare che le creature con `First/Double Strike` stanno per attaccare.
+
+``` java
+rule "510.4 part 1a"
+/*
+Tommaso Romani Nicolò Posta
+February 3, 2022/2023
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $atk: attackingCreatures, $blk: blockingCreatures)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == true)
+ eval($g.stepCombatDamage.getObject() == "510.1a")
+ eval($g.firstStrikeAttaking == false)
+ $allCardsInCombact: (Permanent() from $atk.listReference or Permanent() from $blk.listReference)
+
+ exists(Permanent(
+ (checkKeywordAbility("Double strike") || checkKeywordAbility("First strike"))
+ ) from $allCardsInCombact)
+
+then
+ System.out.println("510.4 part 1a");
+ //Mi salvo la lista di tutti gli attaccanti e difensori di prima
+ System.out.println("Tutti gli attaccanti selezionati "+$atk.listReference);
+
+
+ // copia della lista
+ for(Permanent tmp: $atk.listReference) {
+ $g.stepFirstStikeAttackingCreatures.add(tmp);
+ }
+
+ // ricerca carte first/double strike
+ $atk.listReference.clear();
+ for(Permanent tmp: $g.stepFirstStikeAttackingCreatures) {
+ if (tmp.checkKeywordAbility("First strike") || tmp.checkKeywordAbility("Double strike")){
+ System.out.println("Trovato FIRST/DOUBLE STRIKE da riaggiungere alla lista degli attaccanti");
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ System.out.println("Tutti gli attaccanti selezionati dopo averli salvati " + $g.stepFirstStikeAttackingCreatures);
+ System.out.println("Tutti gli attaccanti selezionati con First Strike" + $atk.listReference);
+
+ $g.firstStrikeAttaking = true;
+ update($g)
+
+end
+```
+#### ***3. Riporta i puntatori delle liste delgi attaccanti in cima alla lista***
+- Controllo di essere ancora nel turno bonus.
+- Controllo di trovarmi ancora nella fase di attacco delle creature con `First/Double Strike` e che `notRedoDamage` sia `false`.
+- Allora sposto i puntatori in cima alle liste, aggiorni il time frame e il game.
+
+
+``` java
+rule "510.4 part 3a"
+/*
+Tommaso Romani Nicolò Posta
+February 3, 2022/2023
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 400
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.DURING_TIME_FRAME)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == true)
+ eval($g.stepCombatDamage.getObject() == "510.3")
+ eval($g.firstStrikeAttaking == true)
+ eval($g.notRedoDamage == true)
+then
+
+ $g.attackingPlayer.toHead();
+ $g.defendingPlayers.toHead();
+
+ $g.attackingCreatures.toHead();
+
+ $g.blockingCreatures.toHead();
+
+ $g.stepCombatDamage.movePointer(0);
+ $g.currentStep.next();
+
+ $g.stepTimeFrame = Game.BEGIN_TIME_FRAME;
+ System.out.println("510.4 part 3a");
+
+ $g.notRedoDamage = false;
+ update($g)
+
+end
+```
+#### ***4. Rimetto a posto le liste delgi attaccanti dopo che si è risolto il turno bonus***
+- Controllo che non ci si trovi più nello step di danno bonus, ma che sia ancora vero `firstStrikeAttacking`.
+- Controllo che si sia già triggerata la ***510.4 part 3a*** tramite `notRedoDamage`.
+- Allora rimetto a posto le liste affinchè possa svolgersi correttamente il turno delle creature che non hanno attaccato nel turno bonus.
+
+``` java
+rule "510.4 part 2a"
+/*
+Tommaso Romani Nicolò Posta
+February 3, 2022/2023
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $atk: attackingCreatures)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == false)
+ eval($g.stepCombatDamage.getObject() == "510.1a")
+ eval($g.firstStrikeAttaking == true)
+ eval($g.notRedoDamage == false)
+then
+ System.out.println("510.4 part 2a");
+
+
+ for(Permanent tmp: $atk.listReference) {
+ $g.auxiliaryListFirstStrike.add(tmp);
+
+ }
+ $atk.listReference.clear();
+
+ // double strike
+ for(Permanent tmp: $g.auxiliaryListFirstStrike) {
+ if (tmp.checkKeywordAbility("Double strike")){
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ for(Permanent tmp: $g.stepFirstStikeAttackingCreatures) {
+ if (!tmp.checkKeywordAbility("First strike") && !tmp.checkKeywordAbility("Double strike")){
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ $g.stepFirstStikeAttackingCreatures.clear();
+
+ for(Permanent tmp: $g.auxiliaryListFirstStrike) {
+ if (!tmp.checkKeywordAbility("Double strike")){
+ $g.stepFirstStikeAttackingCreatures.add(tmp);
+ }
+ }
+ $g.auxiliaryListFirstStrike.clear();
+ $g.firstStrikeAttaking = false;
+ update($g);
+
+end
+```
+#### ***5. Aggiorno i danni subiti nel turno bonus e distruggo le eventuali carte che hanno danni maggiori ti toughness***
+- Controllo di essere ancora nel turno bonus all'ultimo step del danno.
+- Controllo che la regola ***120.3e*** si è triggerata aggiornando la variabile `updateDamage`.
+- Controllo che nel battlefield ci sono permanenti che hanno danni maggiori di `toughness`.
+- Allora distruggo quei permanenti.
+
+``` java
+rule "510.4 update_damage"
+/*
+Tommaso Romani Nicolò Posta
+February 3, 2022/2023
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $bf: battleField)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == false)
+ eval($g.updateDamage == true)
+
+ $pmt: Permanent(
+ cardType[0].contains("creature"),
+ Integer.parseInt(toughness[0]) > 0,
+ Integer.parseInt(toughness[0]) <= markedDamage
+ ) from $bf
+then
+
+ System.out.println("510.4 --> Controlling if there are creatures that have marked damage greater or equal than toughness.");
+ System.out.println($pmt.getNameAsString+" ha toughness "+Integer.parseInt($pmt.toughness[0])+" e danni "+$pmt.markedDamage);
+ System.out.println($pmt.getNameAsString+" viene distrutta");
+ $g.destroy($pmt);
+ System.out.println("----------- TEST 510.4 -----------");
+ $g.updateDamage = false;
+ update($g)
+end
+```
+
+
+
+## ***702.8 Flash*** :flashlight:
+
+### **Descrizione** :mag:
+
+- `.a` _Flash is a static ability that functions in any zone from which you could play the card it's on. "Flash" means "You may play this card any time you could cast an instant."_
+
+- `.b` _702.8b. Multiple instances of flash on the same object are redundant._
+
+### **Implementazione :computer:**
+
+#### 1. Trovare `Flash` nei mazzi
+
+- Quando il **gioco** è nella fase `STARTING_STAGE`,
+- prendiamo tutti i player in gioco e per ognuno prendiamo tutte le **abilità ** di ogni carta che hanno nel mazzo,
+- controlliamo quale di queste ha nel `keyword_text` la parola `flash`.
+- Una volta effettuato questo controllo andiamo ad **impostare**, per ogni carta, le proprietà `keyword_ability` e `static_ability` a `true` della rispettiva abilità .
+
+
+``` java
+rule "702.8a"
+/**
+ Flash is a static ability
+
+ @author Cristian Cosci, Nicolò Vescera
+ @date 2022/2023
+**/
+dialect "mvel"
+no-loop true
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getKeywordAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ keyword_text.toLowerCase().startsWith("flash")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setFlash(true);
+
+ System.out.println("702.8a -> Trovato Flash: " + $c.getName());
+
+ update($p)
+end
+```
+
+
+#### 2. Attivazione di `Flash`
+
+La regola che gestisce le instant è stata modificata nel seguente modo:
+
+- Per ogni carta presente **nella mano del player**,
+- aggiungo un secondo controllo a quello già esistente che aggiunge la carta alla lista delle **possibili carte giocabili** se ha tra le sue abilità `Flash`.
+- Quindi così i controlli andranno ad **"escludersi" a vicenda**: se la carta è già stata aggiunta al primo controllo, risulterà inutile controllare tutte le sue abilità per poi aggiungerla erroneamente una seconda volta.
+
+
+``` java
+// Casting Spells
+rule "601.2a instant"
+/*
+November 19, 2021
+601.2a
+To propose the casting of a spell, a player first moves that card (or that copy of a card) from where it is to the stack. It becomes the topmost
+object on the stack. It has all the characteristics of the card (or the copy of a card) associated with it, and that player becomes its controller.
+The spell remains on the stack until it's countered, it resolves, or an effect moves it elsewhere.
+*/
+
+agenda-group "general"
+dialect "mvel"
+when
+ Game(stage == Game.GAME_STAGE, castingSpell == null)
+
+ $act: Action($id: id, option == Game.CAST_INSTANT_SPELL)
+ $p: Player(id == $id, $hand: hand)
+
+then
+ MakeChoice choice = new MakeChoice();
+ choice.idChoice = 60121;
+ choice.choiceText = "Choose which card to play";
+ boolean found = false;
+ // La ricerca delle carte castabili va fatta in tutte le zone
+ for(Card card : $hand) {
+ boolean foundInHand = false;
+
+ if( card.cardType.size() > 0 &&
+ card.cardType[0].contains("instant") &&
+ !card.cardType[0].contains("land")) {
+ choice.addOption(card.magicTargetId, card.getNameAsString());
+ found = true;
+ foundInHand = true;
+ }
+
+ if (!foundInHand){
+ System.out.println("702.8a -> Sto cercando flash tra le varie zone");
+
+ for (LinkedList abilityList: card.getKeywordAbilities()){
+ for (Ability ability: abilityList){
+ if (ability.hasFlash()) {
+ System.out.println("702.8a -> Carta giocabile con Flash " + card.getNameAsString());
+ choice.addOption(card.magicTargetId, card.getNameAsString());
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if(found) {
+ GameEngine.sendToNode(choice, Game.CHOICE, Game.ONE_OF_CHOICE, $id);
+ GameEngine.sendToNode("The player " + $p.nickname + " wants cast a spell.");
+ System.out.println("The player " + $p.nickname + " wants cast a spell.");
+ } else {
+ GameEngine.sendToNode("You have not instant spells to cast.");
+ System.out.println("601.2a -> The player " + $p.nickname + " has not instant spells to cast.");
+ retract($p.action);
+ $p.action = new Action($id,0,0,0);
+ insert($p.action);
+ }
+end
+```
+
+
+
+## ***702.10 Haste âš¡***
+
+
+### **Descrizione** :mag:
+
+- `.a` _Haste is a static ability._
+
+- `.b` _If a creature has haste, it can attack even if it hasn't been controlled by its controller continuously since their most recent turn began._ (See rule [302.6](https://yawgatog.com/resources/magic-rules/#R3026).)
+
+- `.c` _If a creature has haste, its controller can activate its activated abilities whose cost includes the tap symbol or the untap symbol even if that creature hasn't been controlled by that player continuously since their most recent turn began._ (See rule [302.6](https://yawgatog.com/resources/magic-rules/#R3026).)
+
+- `.d` Multiple instances of haste on the same creature are redundant.
+
+### **Implementazione :computer:**
+
+#### 1. Trovare haste nei mazzi
+
+
+- Quando il **gioco** è nella fase `STARTING_STAGE`,
+- prendiamo tutti i player in gioco e per ognuno prendiamo tutte le **abilità ** di ogni carta che hanno nel mazzo,
+- controlliamo quale di queste ha nel `keyword_text` la parola `haste`.
+- Una volta effettuato questo controllo andiamo ad **impostare**, per ogni carta, le proprietà `keyword_ability` e `static_ability` a `true` della rispettiva abilità .
+
+
+
+
+
+```java
+
+/*
+ Febbraio 2023
+ Haste is a static ability.
+*/
+
+rule "702.10a"
+agenda-group "general"
+dialect "mvel"
+ when
+ $g: Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability == false && abilityText.startsWith("haste")) from $la
+
+ then
+ $a.setStatic_ability(true);
+ System.out.println("Trovato Haste");
+ update($p)
+end
+```
+
+
+
+#### 2. Attivazione di Haste
+
+- Per prima cosa andiamo a **prendere tutte le carte** presenti nel `campo di battaglia`.
+- In seguito selezioniamo solo le carte di tipo _Creatura_ (`cardType[0] == "creature"`), che abbiano l'abilità `Haste` e con il flag `summoningSickness = true`.
+- Infine, per ogni Carta risultante dalla precedente selezione, impostiamo il flag `summoningSickness=false` dato che l'abilità `Haste` va ad **invalidare la summoningSickness.**
+
+
+
+
+
+```java
+/*
+ Febbraio 2023
+
+ If a creature has haste, it can attack even if it hasn't been controlled by its controller continuously since their most recent turn began.
+ (See rule 302.6.)
+
+ If a creature has haste, its controller can activate its activated abilities whose cost includes the tap symbol or the untap symbol
+ even if that creature hasn't been controlled by that player continuously since their most recent turn began.(See rule 302.6.)
+
+ Multiple instances of haste on the same creature are redundant.
+*/
+
+rule "702.10b"
+agenda-group "general"
+no-loop true
+dialect "mvel"
+ when
+ $g: Game(
+ stage == Game.GAME_STAGE,
+ $bf: battleField
+ )
+ $pmt: Permanent(
+ cardType[0].contains("creature"),
+ summoningSickness,
+ checkKeywordAbility("haste")
+ ) from $bf
+ then
+ $pmt.summoningSickness=false;
+ System.out.println("Trovata creatura con haste nel battlefield");
+
+ update($g)
+end
+```
diff --git a/Documentation/2022/logo.png b/Documentation/2022/logo.png
new file mode 100644
index 0000000..e546ea1
Binary files /dev/null and b/Documentation/2022/logo.png differ
diff --git a/README.md b/README.md
index 5d22245..abc3346 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,6 @@ Per riuscire ad importare il progetto in Eclipse seguire i seguenti punti:
1. Clonare il progetto: eseguire il seguente comando in una cartella a tua scelta
```bash
git clone https://github.com/Typing-Monkeys/TeferiTheGathering.git
-
cd TeferiTheGathering
```
@@ -33,5 +32,30 @@ npm start
### Known Issue
-- Può succedere che una volta riaperto Eclipse, questo non riesce a trovare la libreria Drools. In questo caso fai Tasto destro sul progetto, `Properties`, `Drools` e assicurati che la checkbox `Enable project specific settings` **non** sia spuntata.
-In caso guarda questa [issue](https://github.com/Typing-Monkeys/TeferiTheGathering/issues/1)
\ No newline at end of file
+#### **Drools Errors after restart**
+
+Può succedere che una volta riaperto Eclipse, questo non riesce a trovare la libreria Drools. In questo caso fai Tasto destro sul progetto, `Properties`, `Drools` e assicurati che la checkbox `Enable project specific settings` **non** sia spuntata.
+
+In caso guarda questa [issue](https://github.com/Typing-Monkeys/TeferiTheGathering/issues/1).
+
+#### **Git/GitHub-Desktop Windows**
+
+In windows, utilizzare GitHub Desktop e, di conseguenza anche git cli nella powershell/cmd,
+romperà il progetto andando a modificare cose che non dovrebbe, rovina il file Rules.drl
+cambiando indentazione e spaziatura e non ha idea di come gestire le cartelle che iniziano con il `.`.
+L'unico modo per risolvere è **NON** utilizzarlo 🙃 e usare **SOLO** git su un ambiente linux (la WSL va benissimo !).
+Se non hai idea di quale versione di git hai utilizza il seguente comando:
+
+```bash
+git --version
+```
+
+Se in output avrai una roba del tipo:
+
+```
+git 2.83.1-windows.1
+```
+
+stai utilizzando git sbagliato !!
+
+In caso ne avessi bisogno puoi trovare una guida su come abilitare WSL in Windows [qui](https://learn.microsoft.com/it-it/windows/wsl/install)
diff --git a/mtgengine/.DS_Store b/mtgengine/.DS_Store
deleted file mode 100644
index 56da844..0000000
Binary files a/mtgengine/.DS_Store and /dev/null differ
diff --git a/mtgengine/src/.project b/mtgengine/src/.project
new file mode 100644
index 0000000..f7d6de6
--- /dev/null
+++ b/mtgengine/src/.project
@@ -0,0 +1,11 @@
+
+
+ src
+
+
+
+
+
+
+
+
diff --git a/mtgengine/src/main/java/com/magicengine/Ability.java b/mtgengine/src/main/java/com/magicengine/Ability.java
index 44e8af0..4057e6b 100644
--- a/mtgengine/src/main/java/com/magicengine/Ability.java
+++ b/mtgengine/src/main/java/com/magicengine/Ability.java
@@ -9,14 +9,15 @@ public class Ability {
private boolean keyword_ability = false;
private String keyword_text = "";
-
+
private String abilityText = "";
// su ability text inserire il testo fornito dal json
+
+ private boolean trigg_haste = false;
private boolean spell_ability = false; // solo della classe ability on the stack
private boolean triggered_ability = false;
-
//private String targetType = "";
//private MagicObject targetted_obj = null;
private boolean targetted_ability = false;
@@ -43,6 +44,7 @@ public class Ability {
private String activated_instruction =null;
LinkedList manaCostSymbols=null;
+ private boolean flash = false;
//public boolean checkedByDrools = false;
@@ -92,6 +94,19 @@ public void setManaCostSymbols() {
}
this.manaCostSymbols=manaCostSymbols;
}
+
+ public boolean isTrigg_haste() {
+ return trigg_haste;
+ }
+
+ public boolean getTrigg_haste() {
+ return trigg_haste;
+ }
+
+ public void setTrigg_haste(boolean trigg_haste) {
+ this.trigg_haste = trigg_haste;
+ }
+
public LinkedList getActivated_cost() {
@@ -309,8 +324,7 @@ public boolean isAttached_to() {
public void setAttached_to(boolean attached_to) {
this.attached_to = attached_to;
}
-
-
+
public MagicObject getAttached_to_obj() {
return attached_to_obj;
}
@@ -345,8 +359,6 @@ public LinkedList getTargetType() {
return this.targetType;
}
-
-
public boolean cercaTestoNellaStringa(String stringa, String tipo) {
String abilityTextUpper=abilityText.toUpperCase();
@@ -506,8 +518,18 @@ public String toString() {
+ attached_to + ", attached_to_obj=" + attached_to_obj + ", timestamp=" + timestamp
+ ", triggered_condition=" + triggered_condition + ", triggered_effect=" + triggered_effect
+ ", triggered_instruction=" + triggered_instruction + ", activated_cost=" + activated_cost
- + ", activated_effect=" + activated_effect + ", activated_instruction=" + activated_instruction + "]";
+ + ", activated_effect=" + activated_effect + ", activated_instruction=" + activated_instruction
+ + ", trigg_haste" + trigg_haste + "]";
}
+ public boolean hasFlash() {
+ return flash;
+ }
+
+
+ public void setFlash(boolean flash) {
+ this.flash = flash;
+ }
+
}
diff --git a/mtgengine/src/main/java/com/magicengine/Game.java b/mtgengine/src/main/java/com/magicengine/Game.java
index 7d7e0b6..2e133eb 100644
--- a/mtgengine/src/main/java/com/magicengine/Game.java
+++ b/mtgengine/src/main/java/com/magicengine/Game.java
@@ -198,10 +198,16 @@ public class Game {
private ListPointer defendingPlayers;
private ListPointer attackingCreatures;
private ListPointer blockingCreatures;
+ private LinkedList stepFirstStikeAttackingCreatures;
+ private LinkedList stepFirstStikeBlockingCreatures;
+ private LinkedList auxiliaryListFirstStrike;
private ListPointer stepDeclareAttackers;
private ListPointer stepDeclareBlockers;
private ListPointer stepCheckEvasionAbility;
private boolean blockValid; // flag di controllo per validità dei blocchi
+ private boolean firstStrikeAttaking = false; // flag per non far fare danni dai bloccnati senza first strike
+ private boolean notRedoDamage = true;
+ private boolean updateDamage = false;
private ListPointer stepCombatDamage;
private LinkedList possibleTarget;
// --------------------------------------------------------------------------------------
@@ -268,6 +274,9 @@ public Game() {
this.defendingPlayers = new ListPointer(new LinkedList());
this.attackingCreatures = new ListPointer(new LinkedList());
this.blockingCreatures = new ListPointer(new LinkedList());
+ this.stepFirstStikeAttackingCreatures = new LinkedList();
+ this.stepFirstStikeBlockingCreatures = new LinkedList();
+ this.auxiliaryListFirstStrike = new LinkedList();
this.stepDeclareAttackers = new ListPointer(new LinkedList());
this.stepDeclareBlockers = new ListPointer(new LinkedList());
this.stepCheckEvasionAbility = new ListPointer(new LinkedList());
@@ -948,4 +957,54 @@ public boolean isDiscardTurn() {
public void setDiscardTurn(boolean discardTurn) {
this.discardTurn = discardTurn;
}
+
+
+ public boolean isFirstStrikeAttaking() {
+ return firstStrikeAttaking;
+ }
+
+ public void setFirstStrikeAttaking(boolean firstStrikeAttaking) {
+ this.firstStrikeAttaking = firstStrikeAttaking;
+ }
+
+ public boolean getNotRedoDamage() {
+ return notRedoDamage;
+ }
+
+ public void setNotRedoDamage(boolean notRedoDamage) {
+ this.notRedoDamage = notRedoDamage;
+ }
+
+ public List getStepFirstStikeAttackingCreatures() {
+ return stepFirstStikeAttackingCreatures;
+ }
+
+ public void setStepFirstStikeAttackingCreatures(LinkedList stepFirstStikeAttackingCreatures) {
+ this.stepFirstStikeAttackingCreatures = stepFirstStikeAttackingCreatures;
+ }
+
+ public List getStepFirstStikeBlockingCreatures() {
+ return stepFirstStikeBlockingCreatures;
+ }
+
+ public void setStepFirstStikeBlockingCreatures(LinkedList stepFirstStikeBlockingCreatures) {
+ this.stepFirstStikeBlockingCreatures = stepFirstStikeBlockingCreatures;
+ }
+
+ public LinkedList getAuxiliaryListFirstStrike() {
+ return auxiliaryListFirstStrike;
+ }
+
+ public void setAuxiliaryListFirstStrike(LinkedList auxiliaryListFirstStrike) {
+ this.auxiliaryListFirstStrike = auxiliaryListFirstStrike;
+ }
+
+ public boolean isUpdateDamage() {
+ return updateDamage;
+ }
+
+ public void setUpdateDamage(boolean updateDamage) {
+ this.updateDamage = updateDamage;
+ }
+
}
diff --git a/mtgengine/src/main/java/com/magicengine/MagicObject.java b/mtgengine/src/main/java/com/magicengine/MagicObject.java
index e058fce..97bfa72 100644
--- a/mtgengine/src/main/java/com/magicengine/MagicObject.java
+++ b/mtgengine/src/main/java/com/magicengine/MagicObject.java
@@ -287,12 +287,25 @@ public void setColorIndicator(ArrayList> colorIndicator) {
public ArrayList> getCardType() {
- return cardType;
+ ArrayList> lowerCard = (ArrayList>) cardType.clone();
+ lowerCard.get(0).set(0, lowerCard.get(0).get(0).toLowerCase());
+ return lowerCard;
}
public void setCardType(LinkedList cardType) {
- this.cardType.add(cardType);
+ /**
+ * Converte le stringe in lowercase per rendere piu semplici
+ * i controlli in DROOLS
+ */
+ LinkedList listToLower = new LinkedList();
+
+ for(String elem : cardType) {
+ listToLower.add(elem.toLowerCase());
+ }
+ this.cardType.add(listToLower);
+
+ //this.cardType.add(cardType);
}
diff --git a/mtgengine/src/main/java/com/magicengine/Permanent.java b/mtgengine/src/main/java/com/magicengine/Permanent.java
index 9151af3..39b0376 100644
--- a/mtgengine/src/main/java/com/magicengine/Permanent.java
+++ b/mtgengine/src/main/java/com/magicengine/Permanent.java
@@ -29,6 +29,18 @@ public class Permanent extends MagicObject {
// TODO: modificare costruttore ed altri metodi
private LinkedList attackersICanBlock;
+ private boolean deathtouched = false;
+
+ public boolean isDeathtouched() {
+ return deathtouched;
+ }
+
+ public boolean getDeathtouched() {
+ return deathtouched;
+ }
+ public void setDeathtouched(boolean deathtouched) {
+ this.deathtouched = deathtouched;
+ }
@Override
public String toString() {
@@ -457,7 +469,7 @@ public boolean checkKeywordAbility(String keyword_text) {
// TODO: gestire faccia attiva
return this.keywordAbilities.get(0)
.stream()
- .anyMatch((Ability a) -> a.getKeyword_text().trim().equals(keyword_text));
+ .anyMatch((Ability a) -> a.getKeyword_text().trim().toLowerCase().equals(keyword_text.toLowerCase()));
}
@Override
diff --git a/mtgengine/src/main/java/com/magicengine/Player.java b/mtgengine/src/main/java/com/magicengine/Player.java
index cab83e1..b60c103 100644
--- a/mtgengine/src/main/java/com/magicengine/Player.java
+++ b/mtgengine/src/main/java/com/magicengine/Player.java
@@ -143,25 +143,22 @@ public void takeMulligan(int mulliganType)
}
}
- public void discard(MagicObject card) {
- /** Rimuove dalla mano del giocatore la carta specificata (se presente)
+ /**
+ * @author Nicolò Posta, Tommaso Romani, Nicolò Vescera
+ *
+ * Rimuove dalla mano del giocatore la carta specificata (se presente)
* e la posiziona in fondo alla libreria
+ * N.B.: questa regola viene utilizzata (per ora) solo per il mulligan !!
+ *
+ * @param card la carta da mettere in fondo la mazzo
*/
+ public void sendToBottomLibrary(MagicObject card) {
boolean discarded = this.hand.remove(card);
if (discarded) {
this.library.add(card);
}
-
}
- public void discard(int card_index) {
- /** Rimuove dalla mano del giocatore la carta corrispondente
- * all'indice specificato e la posiziona in fondo alla libreria
- */
- MagicObject discarded = this.hand.remove(card_index);
- this.library.add(discarded);
- }
-
public String getNickname() {
return nickname;
}
diff --git a/mtgengine/src/main/resources/rules/Rules.drl b/mtgengine/src/main/resources/rules/Rules.drl
index 2e0331d..49f804a 100644
--- a/mtgengine/src/main/resources/rules/Rules.drl
+++ b/mtgengine/src/main/resources/rules/Rules.drl
@@ -31,7 +31,6 @@ import com.magicengine.RulePriorityCounter;
import java.util.*;
import org.kie.api.runtime.KieSession;
-
rule "updateClients"
dialect "mvel"
agenda-group "general"
@@ -704,7 +703,7 @@ dialect "mvel"
card = $p.hand.get(card_idx);
System.out.println("103.4 part 3c mulligan LONDON discard answer-> Player " + pid + "discarded " + card.getNameAsString());
// Scarto
- $p.discard(card);
+ $p.sendToBottomLibrary(card);
$p.discarding = false;
retract($ca)
update($p)
@@ -1451,6 +1450,7 @@ rule "117.5"
"704.5b",
"704.5c",
"704.5f",
+ "702.2b",
"704.5g",
"704.5i",
"704.5j"
@@ -1551,6 +1551,7 @@ then
$p.markedDamage += $p.damageDealt;
System.out.println($p.getNameAsString()+" ha "+$p.markedDamage+" danni segnati");
$p.damageDealt = 0;
+ $g.updateDamage = true;
update($g);
end
@@ -2325,13 +2326,14 @@ rule "506.1 part 1"
combat damage, and end of combat.*/
agenda-group "initialization"
dialect "mvel"
+ salience 100
when
$p: Player()
- $ph : Phase(this.isEmpty(), name == "combat") from $p.turn
+ $ph : Phase(this.isEmpty(), name == "combat") from $p.turn
then
$ph.add(new Step("beginning of combat",false));
$ph.add(new Step("declare attackers",false));
- $ph.add(new Step("declare blockers",false));
+ $ph.add(new Step("declare blockers",false));
$ph.add(new Step("combat damage",false));
$ph.add(new Step("end of combat",false));
System.out.println("Rule 506.1 --> Player: "+$p.getNickname());
@@ -2354,14 +2356,35 @@ end
rule "506.1 part 3"
-/*
---- November 19, 2021 ---
+/* Tommaso Romani Nicol� Posta
There are two combat damage steps if any attacking or blocking creature has first strike
(see rule 702.7) or double strike (see rule 702.4).*/
dialect "mvel"
+salience 50
+no-loop true
+agenda-group "general"
when
- Game(stage == Game.GAME_STAGE);
+ $g:Game(stage == Game.GAME_STAGE, $bf: battleField, $ph: currentPhase.getObject())
+ eval($g.currentPhase.getObject().name == "combat")
+ eval($ph.size() <= 5)
+ //TODO: mettere che siano tra gli attaccanti o i bloccanti
+ exists (Permanent(
+ (checkKeywordAbility("Double strike") || checkKeywordAbility("First strike"))
+ ) from $bf)
then
+ System.out.println("506.1 part 3 -> Aggiunto combat damage per First/Double strike");
+
+ $ph.remove($ph.size()-1);
+ $ph.remove($ph.size()-1);
+ $ph.add(new Step("combat damage",true));
+ $ph.add(new Step("combat damage",false));
+ $ph.add(new Step("end of combat",false));
+ System.out.println("Size prima dell'aggiunta" + $ph.size());
+
+
+
+ update($g)
+
end
@@ -2687,10 +2710,24 @@ then
choice.choiceText = "Choose which creature will attack";
boolean found = false;
choice.addOption(-1, "No attack");
+
+ /*
+ Rule 702.3b. A creature with defender can't attack.
+ */
for(Permanent permanent : $g.battleField) {
if(permanent.idController == $id && !permanent.getStatus().isTapped() && !permanent.summoningSickness && permanent.cardType[0].contains("creature")){
- choice.addOption(permanent.magicTargetId, permanent.getNameAsString());
- found = true;
+ boolean nodefender = true;
+
+ // Defender check of the selected permanent.
+ if (permanent.checkKeywordAbility("Defender")){
+ System.out.println("702.3b -> Card has Defender, can't attack !");
+ nodefender = false;
+ }
+
+ if (nodefender){
+ choice.addOption(permanent.magicTargetId, permanent.getNameAsString());
+ found = true;
+ }
}
}
if(found){
@@ -4162,13 +4199,16 @@ when
$g: Game($scd: stepCombatDamage.listReference)
eval($scd.size()==0)
then
+ System.out.println("510.1 -> Aggiunti step per il combat damage");
+ // aggiungere prima una regola che controlla se c'� o non c'� double/first, se c'� crea la lista con queste 3 aggiunte
$scd.add("510.1a");
$scd.add("510.1bc");
+ //$scd.add("702.2b");
$scd.add("510.1d");
//$scd.add("510.1e");
$scd.add("510.2");
$scd.add("510.3");
- $scd.add("510.4");
+ //$scd.add("510.4");
$g.stepCombatDamage.next();
update($g);
end
@@ -4190,28 +4230,50 @@ when
then
System.out.println("510.1a -> calcola combat damage da power");
int powerInt = 0;
+
for(Permanent attacker : $g.attackingCreatures.listReference){
- powerInt = Integer.parseInt(attacker.power[0]);
- if(powerInt<=0){
+ if($g.firstStrikeAttaking == true && !((!attacker.checkKeywordAbility("First strike") && attacker.checkKeywordAbility("Double strike"))||((attacker.checkKeywordAbility("First strike") && !attacker.checkKeywordAbility("Double strike"))))){
attacker.damageToAssign = 0;
- System.out.println(attacker.getNameAsString()+" ha "+attacker.damageToAssign+" danni");
+ System.out.println(attacker.getNameAsString()+" non fa danni perchè non ha First/Double Strike");
} else {
- attacker.damageToAssign = powerInt;
- System.out.println(attacker.getNameAsString()+" ha "+attacker.damageToAssign+" danni");
+ powerInt = Integer.parseInt(attacker.power[0]);
+ if(powerInt<=0){
+ attacker.damageToAssign = 0;
+ System.out.println(attacker.getNameAsString()+" ha "+attacker.damageToAssign+" danni");
+ } else {
+ attacker.damageToAssign = powerInt;
+ System.out.println(attacker.getNameAsString()+" ha "+attacker.damageToAssign+" danni");
+ }
}
}
for(Permanent blocker : $g.blockingCreatures.listReference){
- powerInt = Integer.parseInt(blocker.power[0]);
- if(powerInt<=0){
+ if($g.notRedoDamage == false && blocker.checkKeywordAbility("First strike")){
blocker.damageToAssign = 0;
- System.out.println(blocker.getNameAsString()+" ha "+blocker.damageToAssign+" danni");
+ System.out.println(blocker.getNameAsString()+" non fa danni da difensore perchè li ha fatti prima con First Strike");
} else {
- blocker.damageToAssign = powerInt;
- System.out.println(blocker.getNameAsString()+" ha "+blocker.damageToAssign+" danni");
+ if($g.firstStrikeAttaking == true && !((!blocker.checkKeywordAbility("First strike") && blocker.checkKeywordAbility("Double strike"))||((blocker.checkKeywordAbility("First strike") && !blocker.checkKeywordAbility("Double strike"))))){
+ blocker.damageToAssign = 0;
+ System.out.println(blocker.getNameAsString()+" non fa danni da difensore perchè non ha First/Double Strike");
+ } else {
+ powerInt = Integer.parseInt(blocker.power[0]);
+ if(powerInt<=0){
+ blocker.damageToAssign = 0;
+ System.out.println(blocker.getNameAsString()+" ha "+blocker.damageToAssign+" danni");
+ } else {
+ blocker.damageToAssign = powerInt;
+ System.out.println(blocker.getNameAsString()+" ha "+blocker.damageToAssign+" danni");
+ }
+ }
}
}
- $g.attackingCreatures.movePointer(0);
+
+ if($g.attackingCreatures.listReference.size() > 0){
+ $g.attackingCreatures.movePointer(0);
+ }
+
+ System.out.println("510.1a -> indice attuale di step: "+ $g.currentStep.getObject().name);
+ System.out.println("510.1a -> step addizionale? "+ $g.currentStep.getObject().additional);
$g.stepCombatDamage.next();
update($g);
end
@@ -4666,6 +4728,7 @@ November 19, 2021
510.3. Third, the active player gets priority. (See rule 117, "Timing and Priority.")*/
agenda-group "general"
dialect "mvel"
+salience 500
when
$g:Game(stage == Game.GAME_STAGE, $ac : activePlayer, stepTimeFrame == Game.BEGIN_TIME_FRAME)
eval($g.currentStep.getObject().name == "combat damage")
@@ -4693,22 +4756,191 @@ rule "510.3a"
end
-rule "510.4"
- /*
- November 19, 2021
- 510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
- only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
- combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
- that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
- double strike. After that step, the phase proceeds to the end of combat step.*/
- agenda-group "general"
- dialect "mvel"
- when
- $g:Game(stage == Game.GAME_STAGE)
- then
+
+rule "510.4 part 1a"
+/*
+Tommaso Romani Nicol� Posta
+November 19, 2021
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $atk: attackingCreatures, $blk: blockingCreatures)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == true)
+ eval($g.stepCombatDamage.getObject() == "510.1a")
+ eval($g.firstStrikeAttaking == false)
+ $allCardsInCombact: (Permanent() from $atk.listReference or Permanent() from $blk.listReference)
+
+ exists(Permanent(
+ (checkKeywordAbility("Double strike") || checkKeywordAbility("First strike"))
+ ) from $allCardsInCombact)
+
+then
+ System.out.println("510.4 part 1a");
+ //Mi salvo la lista di tutti gli attaccanti e difensori di prima
+ System.out.println("Tutti gli attaccanti selezionati "+$atk.listReference);
+
+
+ // copia della lista
+ for(Permanent tmp: $atk.listReference) {
+ $g.stepFirstStikeAttackingCreatures.add(tmp);
+ }
+
+ // ricerca carte first/double strike
+ $atk.listReference.clear();
+ for(Permanent tmp: $g.stepFirstStikeAttackingCreatures) {
+ if (tmp.checkKeywordAbility("First strike") || tmp.checkKeywordAbility("Double strike")){
+ System.out.println("Trovato FIRST/DOUBLE STRIKE da riaggiungere alla lista degli attaccanti");
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ System.out.println("Tutti gli attaccanti selezionati dopo averli salvati " + $g.stepFirstStikeAttackingCreatures);
+ System.out.println("Tutti gli attaccanti selezionati con First Strike" + $atk.listReference);
+
+ $g.firstStrikeAttaking = true;
+ update($g)
+
end
+
+rule "510.4 part 2a"
+/*
+Tommaso Romani Nicol� Posta
+November 19, 2021
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $atk: attackingCreatures)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == false)
+ eval($g.stepCombatDamage.getObject() == "510.1a")
+ eval($g.firstStrikeAttaking == true)
+ eval($g.notRedoDamage == false)
+then
+ System.out.println("510.4 part 2a");
+
+
+ for(Permanent tmp: $atk.listReference) {
+ $g.auxiliaryListFirstStrike.add(tmp);
+
+ }
+ $atk.listReference.clear();
+
+ // double strike
+ for(Permanent tmp: $g.auxiliaryListFirstStrike) {
+ if (tmp.checkKeywordAbility("Double strike")){
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ for(Permanent tmp: $g.stepFirstStikeAttackingCreatures) {
+ if (!tmp.checkKeywordAbility("First strike") && !tmp.checkKeywordAbility("Double strike")){
+ $atk.listReference.add(tmp);
+ }
+ }
+
+ $g.stepFirstStikeAttackingCreatures.clear();
+
+ for(Permanent tmp: $g.auxiliaryListFirstStrike) {
+ if (!tmp.checkKeywordAbility("Double strike")){
+ $g.stepFirstStikeAttackingCreatures.add(tmp);
+ }
+ }
+ $g.auxiliaryListFirstStrike.clear();
+ $g.firstStrikeAttaking = false;
+ update($g);
+
+end
+
+rule "510.4 part 3a"
+/*
+Tommaso Romani Nicol� Posta
+November 19, 2021
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 400
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.DURING_TIME_FRAME)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == true)
+ eval($g.stepCombatDamage.getObject() == "510.3")
+ eval($g.firstStrikeAttaking == true)
+ eval($g.notRedoDamage == true)
+then
+
+ $g.attackingPlayer.toHead();
+ $g.defendingPlayers.toHead();
+
+ $g.attackingCreatures.toHead();
+
+ $g.blockingCreatures.toHead();
+
+ $g.stepCombatDamage.movePointer(0);
+ $g.currentStep.next();
+
+ $g.stepTimeFrame = Game.BEGIN_TIME_FRAME;
+ System.out.println("510.4 part 3a");
+
+ $g.notRedoDamage = false;
+ update($g)
+
+end
+
+
+
+rule "510.4 update_damage"
+/*
+Tommaso Romani Nicol� Posta
+November 19, 2021
+510.4. If at least one attacking or blocking creature has first strike (see rule 702.7) or double strike (see rule 702.4) as the combat damage step begins, the
+only creatures that assign combat damage in that step are those with first strike or double strike. After that step, instead of proceeding to the end of
+combat step, the phase gets a second combat damage step. The only creatures that assign combat damage in that step are the remaining attackers and blockers
+that had neither first strike nor double strike as the first combat damage step began, as well as the remaining attackers and blockers that currently have
+double strike. After that step, the phase proceeds to the end of combat step.*/
+agenda-group "general"
+dialect "mvel"
+no-loop true
+salience 500
+when
+ $g:Game(stage == Game.GAME_STAGE, stepTimeFrame == Game.BEGIN_TIME_FRAME, $bf: battleField)
+ eval($g.currentStep.getObject().name == "combat damage" && $g.currentStep.getObject().additional == false)
+ eval($g.updateDamage == true)
+
+ $pmt: Permanent(
+ cardType[0].contains("creature"),
+ Integer.parseInt(toughness[0]) > 0,
+ Integer.parseInt(toughness[0]) <= markedDamage
+ ) from $bf
+then
+
+ System.out.println("510.4 --> Controlling if there are creatures that have marked damage greater or equal than toughness.");
+ System.out.println($pmt.getNameAsString+" ha toughness "+Integer.parseInt($pmt.toughness[0])+" e danni "+$pmt.markedDamage);
+ System.out.println($pmt.getNameAsString+" viene distrutta");
+ $g.destroy($pmt);
+ System.out.println("----------- TEST 510.4 -----------");
+ $g.updateDamage = false;
+ update($g)
+end
+
//END OF COMBAT STEP
rule "511.1"
@@ -4775,6 +5007,10 @@ then
$g.stepDeclareAttackers.movePointer(0);
$g.stepDeclareBlockers.movePointer(0);
$g.stepCombatDamage.movePointer(0);
+
+ $g.auxiliaryListFirstStrike.clear();
+ $g.stepFirstStikeAttackingCreatures.clear();
+ $g.notRedoDamage = true;
for(Step step : $g.currentStep.listReference){
if(step.name == "declare blockers" || step.name == "combat damage"){
@@ -4893,7 +5129,7 @@ maximum hand size (normally seven), he or she discards enough cards to reduce
his or her hand size to that number. This turn-based action doesnt use the
stack.
-Edited by Nicolò Posta, Tommaso Romani, Nicolò Vescera, Fabrizio Fagiolo, Cristian Cosci.
+Edited by Nicol� Posta, Tommaso Romani, Nicol� Vescera, Fabrizio Fagiolo, Cristian Cosci.
*/
agenda-group "general"
salience 300
@@ -4919,7 +5155,7 @@ maximum hand size (normally seven), he or she discards enough cards to reduce
his or her hand size to that number. This turn-based action doesnt use the
stack.
-Edited by Nicolò Posta, Tommaso Romani, Nicolò Vescera, Fabrizio Fagiolo, Cristian Cosci.
+Edited by Nicol� Posta, Tommaso Romani, Nicol� Vescera, Fabrizio Fagiolo, Cristian Cosci.
*/
agenda-group "general"
salience 200
@@ -4952,7 +5188,7 @@ maximum hand size (normally seven), he or she discards enough cards to reduce
his or her hand size to that number. This turn-based action doesnt use the
stack.
-Edited by Nicolò Posta, Tommaso Romani, Nicolò Vescera, Fabrizio Fagiolo, Cristian Cosci.
+Edited by Nicol� Posta, Tommaso Romani, Nicol� Vescera, Fabrizio Fagiolo, Cristian Cosci.
*/
agenda-group "general"
salience 100
@@ -4963,7 +5199,7 @@ when
$ca: ChoiceAnswer(idChoice == Game.DISCARD_TO_MAXHANDSIZE, idPlayer == $p.id)
then
- //elimina le carte solo se è stato scelto il numero corretto di carte
+ //elimina le carte solo se � stato scelto il numero corretto di carte
if ($ca.getIdOptions().size() == ($p.getHand().size() - $p.getMaxHandSize())) {
for(String cardId : $ca.getIdOptions()) {
$p.hand.remove(cardId);
@@ -5086,21 +5322,42 @@ agenda-group "general"
dialect "mvel"
when
Game(stage == Game.GAME_STAGE, castingSpell == null)
+
$act: Action($id: id, option == Game.CAST_INSTANT_SPELL)
- $p: Player(id == $id)
+ $p: Player(id == $id, $hand: hand)
+
then
MakeChoice choice = new MakeChoice();
choice.idChoice = 60121;
choice.choiceText = "Choose which card to play";
boolean found = false;
// La ricerca delle carte castabili va fatta in tutte le zone
- for(Card card : $p.hand) {
- if(card.cardType.size() > 0 && card.cardType[0].contains("instant")
- && !card.cardType[0].contains("land")) {
- choice.addOption(card.magicTargetId, card.getNameAsString());
- found = true;
+ for(Card card : $hand) {
+ boolean foundInHand = false;
+
+ if( card.cardType.size() > 0 &&
+ card.cardType[0].contains("instant") &&
+ !card.cardType[0].contains("land")) {
+ choice.addOption(card.magicTargetId, card.getNameAsString());
+ found = true;
+ foundInHand = true;
+ }
+
+ if (!foundInHand){
+ System.out.println("702.8a -> Sto cercando flash tra le varie zone");
+
+ for (LinkedList abilityList: card.getKeywordAbilities()){
+ for (Ability ability: abilityList){
+ if (ability.hasFlash()) {
+ System.out.println("702.8a -> Carta giocabile con Flash " + card.getNameAsString());
+ choice.addOption(card.magicTargetId, card.getNameAsString());
+ found = true;
+ }
+ }
+ }
}
}
+
if(found) {
GameEngine.sendToNode(choice, Game.CHOICE, Game.ONE_OF_CHOICE, $id);
GameEngine.sendToNode("The player " + $p.nickname + " wants cast a spell.");
@@ -5186,7 +5443,9 @@ then
$g.castingSpell = s;
}
}
+
$p.hand.remove($g.castingSpell.originCard);
+
GameEngine.sendToNode("The player " + $p.nickname + " choosen to cast " + $g.castingSpell.name);
System.out.println("601.2a -> The player " + $p.nickname + " choosen to cast " + $g.castingSpell.name);
retract($ca);
@@ -7026,6 +7285,30 @@ To destroy a permanent, move it from the battlefield to its owner's graveyard.
end
+rule "702.3a"
+/*
+ 9th January 2023
+ 702.3a. Defender is a static ability.
+*/
+dialect "mvel"
+no-loop true
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck, $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && abilityText.startsWith("Defender")) from $la
+ then
+ System.out.println("702.3a -> Trovata Defender");
+ $a.setKeyword_ability(true);
+ $a.setStatic_ability(true);
+ //$a.setDefender(true);
+ //$a.setKeyword_text("defender");
+ update($p)
+end
+
+
rule "704.3"
/*
--- November 19, 2021 ---
@@ -7190,7 +7473,7 @@ it ceases to exist.
end
-rule "704.5f"
+rule "704.5f" //non trigghera :+1
/*
November 19, 2021
704.5f. If a creature has toughness 0 or less, it's put into its owner's graveyard.
@@ -7207,7 +7490,12 @@ Regeneration can't replace this event.
then
System.out.println("704.5f --> Controlling if there are creature that have toughness lower or equal than zero.");
for (Permanent p : $bf) {
- if (p.cardType[0].contains("creature") && Integer.parseInt(p.toughness[0]) <= 0) {
+ if(p.deathtouched){
+ System.out.println(p.getNameAsString + " ha Deathtouch !");
+ System.out.println(p.getNameAsString + " viene distrutta");
+ $g.destroy(p);
+ }
+ else if (p.cardType[0].contains("creature") && Integer.parseInt(p.toughness[0]) <= 0) {
System.out.println(p.getNameAsString + " ha toughness minore di 0");
System.out.println(p.getNameAsString + " viene distrutta");
$g.destroy(p);
@@ -7731,6 +8019,145 @@ agenda-group "general"
end
+rule "702.2a"
+/**
+ Deathtouch is a static ability.
+
+ @date 2022/2023
+ @author Cristian Cosci, Fabrizio Fagiolo, Nicolò Vescera
+**/
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ abilityText.toLowerCase().startsWith("deathtouch")) from $la
+ then
+ $a.setStatic_ability(true);
+ System.out.println("702.2a -> Trovato Deathtouch: " + $c.getName());
+
+ update($p)
+end
+
+
+rule "702.2b"
+/**
+ A creature with toughness greater than 0 that s been dealt damage by a source with deathtouch since the
+ last time state-based actions were checked is destroyed as a state-based action.
+ See rule 704.
+
+ @date 2022/2023
+ @author Cristian Cosci, Fabrizio Fagiolo, Nicolò Vescera
+**/
+dialect "mvel"
+salience 500
+no-loop true
+agenda-group "general"
+when
+ $g: Game(
+ stage == Game.GAME_STAGE,
+ $bf : battleField,
+ $attaccanti: attackingCreatures.listReference,
+ $bloccanti: blockingCreatures.listReference,
+ controlStateBasedActions
+ )
+
+ // contiene tutte le carte in combattimento (bloccanti e attaccanti)
+ $allCardsInCombact: (Permanent() from $attaccanti or Permanent() from $bloccanti)
+ $pmt: Permanent (
+ cardType[0].contains("creature"),
+ deathtouched == true
+ ) from $allCardsInCombact
+
+ then
+ System.out.println("702.2b --> Morte per Deathtouch.");
+ System.out.println("\t" + $pmt.getNameAsString+" subisce Deathtouch !");
+ System.out.println("\t" + $pmt.getNameAsString+" viene distrutta");
+
+ GameEngine.sendToNode("La carta " + $pmt.getNameAsString + " viene distrutta per Deathtouch!");
+
+ $g.destroy($pmt);
+
+ update($g)
+end
+
+
+rule "702.2c"
+/**
+ Any nonzero amount of combat damage assigned to a creature by a source with deathtouch is considered to
+ be lethal damage for the purposes of determining if a proposed combat damage assignment is valid,
+ regardless of that creature s toughness.
+ See rules 510.1c-d.
+
+ @date 2022/2023
+ @author Cristian Cosci, Fabrizio Fagiolo, Nicolò Vescera
+**/
+dialect "mvel"
+salience 600
+no-loop true
+agenda-group "general"
+ when
+ $g:Game(
+ stage == Game.GAME_STAGE,
+ stepTimeFrame == Game.BEGIN_TIME_FRAME,
+ $bf: battleField,
+ $blk: blockingCreatures,
+ $atk: attackingCreatures
+ )
+ eval($g.currentStep.getObject().name == "combat damage")
+ eval($g.stepCombatDamage.getObject() == "510.2")
+
+ // contiene tutte le carte in combattimento (bloccanti e attaccanti)
+ $allCardsInCombact: ( Permanent() from $atk.listReference or Permanent() from $blk.listReference)
+ $pmt: Permanent(
+ $difensori: blockedCreatures.listReference,
+ $attaccanti: blockedBy.listReference,
+ cardType[0].contains("creature"),
+ Integer.parseInt(toughness[0]) > 0,
+ combatDamage > 0,
+ //markedDamage > 0,
+ //damageDealt > 0,
+ deathtouched == false
+ ) from $allCardsInCombact
+
+ exists (
+ Permanent(cardType[0].contains("creature") && checkKeywordAbility("Deathtouch")) from $difensori or
+ Permanent(cardType[0].contains("creature") && checkKeywordAbility("Deathtouch")) from $attaccanti
+ )
+
+ then
+ System.out.println("702.2c --> Marchiamento Deathtouch.");
+ System.out.println("\t" + $pmt.getNameAsString+" viene marchiata con Deathtouch !");
+
+ $pmt.setDeathtouched(true);
+
+ update($g)
+end
+
+rule "702.4a"
+/**
+ @date 2022/2023
+ @author Tommaso Romani, Nicol� Posta
+**/
+/*Double Strike is a static ability.*/
+agenda-group "general"
+//no-loop true
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ abilityText.toLowerCase().contains("double strike")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setKeyword_ability(true);
+ $a.setKeyword_text("double strike");
+ System.out.println("702.4a -> Trovato Double Strike: " + $c.getName());
+ update($p)
+end
//martina-damiano cerco keyword ability equip tra le abilità attivate e setto il booleano
@@ -7757,6 +8184,56 @@ agenda-group "general"
end
//è as a sorcery e targetted
+rule "702.8a"
+/**
+ Flash is a static ability
+
+ @author Cristian Cosci, Nicolò Vescera
+ @date 2022/2023
+**/
+dialect "mvel"
+no-loop true
+agenda-group "general"
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getKeywordAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ keyword_text.toLowerCase().startsWith("flash")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setFlash(true);
+
+ System.out.println("702.8a -> Trovato Flash: " + $c.getName());
+
+ update($p)
+end
+
+
+rule "702.7a"
+/**
+ @date 2022/2023
+ @author Tommaso Romani, Nicol� Posta
+**/
+/*First Strike is a static ability.*/
+agenda-group "general"
+//no-loop true
+ when
+ $g : Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability==false &&
+ abilityText.toLowerCase().contains("first strike")) from $la
+ then
+ $a.setStatic_ability(true);
+ $a.setKeyword_ability(true);
+ $a.setKeyword_text("first strike");
+ System.out.println("702.7a -> Trovato First Strike: " + $c.getName());
+ update($p)
+end
+
rule "702.9a"
/*
@@ -7819,7 +8296,43 @@ agenda-group "general"
update($g)
end
+rule "702.10a"
+agenda-group "general"
+dialect "mvel"
+ when
+ $g: Game(stage == Game.STARTING_STAGE)
+ $p : Player($id : id, $nickname: nickname, $deck: deck; $lib: library, library.size() > 0);
+ $c : Card() from $lib
+ $la: LinkedList() from $c.getAbilities()
+ $a : Ability(keyword_ability==false && static_ability == false && abilityText.startsWith("haste")) from $la
+
+ then
+ $a.setStatic_ability(true);
+ System.out.println("Trovato Haste");
+ update($p)
+end
+
+rule "702.10b"
+agenda-group "general"
+no-loop true
+dialect "mvel"
+ when
+ $g: Game(
+ stage == Game.GAME_STAGE,
+ $bf: battleField
+ )
+ $pmt: Permanent(
+ cardType[0].contains("creature"),
+ summoningSickness,
+ checkKeywordAbility("haste")
+ ) from $bf
+ then
+ $pmt.summoningSickness=false;
+ System.out.println("Trovata creatura con haste nel battelfied");
+
+ update($g)
+end
rule "702.13.a"
diff --git a/mtgengine/target/.gitignore b/mtgengine/target/.gitignore
index c426216..77dc284 100644
--- a/mtgengine/target/.gitignore
+++ b/mtgengine/target/.gitignore
@@ -1,3 +1,2 @@
-/META-INF/
/com/
/rules/
diff --git a/mtgengine/target/META-INF/kmodule.xml b/mtgengine/target/META-INF/kmodule.xml
new file mode 100644
index 0000000..6e0d4b2
--- /dev/null
+++ b/mtgengine/target/META-INF/kmodule.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/mtgengine/target/META-INF/maven/pom.properties b/mtgengine/target/META-INF/maven/pom.properties
new file mode 100644
index 0000000..ae24673
--- /dev/null
+++ b/mtgengine/target/META-INF/maven/pom.properties
@@ -0,0 +1,3 @@
+groupId=com.magicengine
+artifactId=MagicGame
+version=1
\ No newline at end of file
diff --git a/mtggameinterface/.DS_Store b/mtggameinterface/.DS_Store
deleted file mode 100644
index af0acd0..0000000
Binary files a/mtggameinterface/.DS_Store and /dev/null differ
diff --git a/mtggameinterface/clientL.html b/mtggameinterface/clientL.html
index 1205c9c..76c0dac 100644
--- a/mtggameinterface/clientL.html
+++ b/mtggameinterface/clientL.html
@@ -77,6 +77,7 @@