From c75446c62d333427a53ea0821d8ad8e705446aab Mon Sep 17 00:00:00 2001
From: edani95 <elekdani95@gmail.com>
Date: Fri, 13 May 2016 20:56:09 +0200
Subject: [PATCH] Bug fixes, communication changes

Communication changes:
- Field, Model and GameController get the option to communicate about
  the changed fields, so it's not neccessary to update the whole map
  every time something changed
  This new communication use PropertyChangeSupport and Listener pattern

Bug fixes:
- No more ConcurrentModificationException when player shoot
- Portal can open
- Portal has its function, so it works as a portal not just a decor
- Player's shoots works as it needs to work

Smaller changes:
- Inverse direction function goes to Direction class
- Testmap improves
---
 core/app/GameController.java         |  60 +++----
 core/app/InitController.java         |  21 +--
 core/game/Direction.java             |  12 ++
 core/game/Model.java                 |  58 ++++++-
 core/mapobjs/defobjs/Door.java       |  10 +-
 core/mapobjs/defobjs/Field.java      | 232 +++++++++++++++------------
 core/mapobjs/defobjs/Portal.java     |  66 ++++----
 core/mapobjs/defobjs/Ravine.java     |   1 -
 core/mapobjs/defobjs/Wall.java       |  10 +-
 core/mapobjs/movobjs/Player.java     |  38 +++--
 core/mapobjs/movobjs/Replicator.java |  13 +-
 core/maps/testmap.txt                |  13 +-
 12 files changed, 330 insertions(+), 204 deletions(-)

diff --git a/core/app/GameController.java b/core/app/GameController.java
index e4f22ec..eb7218f 100644
--- a/core/app/GameController.java
+++ b/core/app/GameController.java
@@ -1,6 +1,8 @@
 package app;
 
 import java.awt.event.KeyEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.util.ArrayList;
 
 import exceptions.GameRunningException;
@@ -14,14 +16,16 @@ import mapobjs.movobjs.Player;
 import view.View;
 import view.ViewElement;
 
-public class GameController {
+public class GameController implements PropertyChangeListener{
 	private View view;
 	private ArrayList<IElement>[][] map;
 	
+	@SuppressWarnings("unchecked")
 	public GameController(View view, int width, int height)
 	{
 		this.view = view;
-		map = InitController.map;
+		map = new ArrayList[InitController.map.length][InitController.map[0].length];
+		Model.getInstance().addPropertyChangeListener(this);
 	}
 	
 	public void startGameProcess() throws GameRunningException
@@ -220,56 +224,32 @@ public class GameController {
 	private void move(Player player)
 	{
 		player.step();
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void turn(Player player, Direction dir)
 	{
 		player.setDirection(dir);
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void shoot(Player player, PortalColor color)
 	{
 		player.fire(color);
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void boxDown(Player player)
 	{
 		player.putBoxDown();
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void boxUp(Player player)
 	{
 		player.getBoxUp();
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void moveReplicator()
 	{
 		Model.getInstance().getReplicator().setDirection(Direction.getRandomDir());
 		Model.getInstance().getReplicator().step();
-		updateGameControllerMap();
-		ArrayList<ViewElement>[][] viewMap = uploadToView();
-		
-		view.setMap(viewMap);
 	}
 	
 	private void endProcess()
@@ -278,6 +258,32 @@ public class GameController {
 		InitController.startJaffaZPMs += Model.getInstance().getJaffa().getZpmCount();
 	}
 	
+	@Override
+	public void propertyChange(PropertyChangeEvent evt) {
+		if(evt.getPropertyName().equals("error"))	// update the whole map as before
+		{
+			updateGameControllerMap();
+			ArrayList<ViewElement>[][] viewMap = uploadToView();
+			view.setMap(viewMap);
+			
+			return;
+		}
+		
+			// update only the changed field
+		int coord = (int)evt.getNewValue();
+		int xCoord = coord / map[0].length;
+		int yCoord = coord % map[0].length;
+		Field changedField = (Field)evt.getOldValue();
+		ArrayList<ViewElement> fieldView = new ArrayList<>();
+		
+		for(int i = 0; i < changedField.getElementNum(); i++)
+		{
+			fieldView.add(Controller.getViewOf(changedField.getElement(i)));
+		}
+		
+		view.setElement(yCoord, xCoord, fieldView);
+	}
+	
 	@SuppressWarnings("unchecked")
 	private void updateGameControllerMap()
 	{
@@ -328,5 +334,5 @@ public class GameController {
 		}
 
 		return mapView;
-	} 
+	}
 }
diff --git a/core/app/InitController.java b/core/app/InitController.java
index 5be97e9..a5fa007 100644
--- a/core/app/InitController.java
+++ b/core/app/InitController.java
@@ -514,7 +514,7 @@ public class InitController {
 							if(map[x][y].get(i) instanceof Portal)
 							{
 								Portal tmp = (Portal)map[x][y].get(i);
-								if(tmp.side() == convertToDir(params.get(4)))
+								if(tmp.getSide() == convertToDir(params.get(4)))
 								{
 									return false;
 								}
@@ -556,11 +556,11 @@ public class InitController {
 							tmpNew.setDirection(convertToDir(params.get(4)));
 							if(tmpPair != null)
 							{
-								tmpPair.setOtherSide(tmpNew);
-								tmpNew.setOtherSide(tmpPair);
+								tmpNew.setOtherSide(tmpPair, false);
 							}
 							map[x][y].add(tmpNew);
-							((Wall)map[x][y].get(hasWall)).meet(new Bullet(null, convertToColor(params.get(3)), convertToInverse(convertToDir(params.get(4)))));
+							((Wall)map[x][y].get(hasWall)).meet(
+									new Bullet(null, convertToColor(params.get(3)), Direction.convertToInverse(convertToDir(params.get(4)))));
 						}
 					}
 				}
@@ -948,17 +948,4 @@ public class InitController {
 		default: throw new InvalidParameterFormatException();
 		}
 	}
-
-	// TODO: belerakni Directionbe
-	private static Direction convertToInverse(Direction dir)
-	{
-		switch(dir)
-		{
-		case UP: return Direction.DOWN;
-		case DOWN: return Direction.UP;
-		case RIGHT: return Direction.LEFT;
-		case LEFT: return Direction.RIGHT;
-		default: return null;
-		}
-	}
 }
\ No newline at end of file
diff --git a/core/game/Direction.java b/core/game/Direction.java
index 24a3b47..286cb15 100644
--- a/core/game/Direction.java
+++ b/core/game/Direction.java
@@ -23,6 +23,18 @@ public enum Direction {
 		default: return UP;
 		}
 	}
+	
+	public static Direction convertToInverse(Direction dir)
+	{
+		switch(dir)
+		{
+		case UP: return Direction.DOWN;
+		case DOWN: return Direction.UP;
+		case RIGHT: return Direction.LEFT;
+		case LEFT: return Direction.RIGHT;
+		default: return null;
+		}
+	}
 
 	@Override
 	public String toString()
diff --git a/core/game/Model.java b/core/game/Model.java
index 6bc7b33..2f1df33 100644
--- a/core/game/Model.java
+++ b/core/game/Model.java
@@ -1,5 +1,8 @@
 package game;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 import java.util.Random;
 
@@ -10,8 +13,10 @@ import mapobjs.defobjs.ZPM;
 import mapobjs.movobjs.Player;
 import mapobjs.movobjs.Replicator;
 
-public class Model
+public class Model implements PropertyChangeListener
 {
+	private final PropertyChangeSupport propSupp = new PropertyChangeSupport(this);
+	
 	private ArrayList<Field> map = new ArrayList<Field>();
 	private Player colonel;
 	private Player jaffa;
@@ -19,7 +24,6 @@ public class Model
 	private Door specDoor;
 	private int specOpen = 1;
 	private Replicator replicator;
-	//private Gate mainGate;
 	private boolean isMapFinished = false;
 
 	public void setSpecDoor(Door specDoor) {
@@ -37,7 +41,14 @@ public class Model
 	        }
 	    }
 	    return instance;
-
+	}
+	
+	public void addPropertyChangeListener(PropertyChangeListener listener)
+	{
+		if(listener != null)
+		{
+			propSupp.addPropertyChangeListener(listener);
+		}
 	}
 
 	public void setColonel(Player colonel)
@@ -53,6 +64,7 @@ public class Model
 
 	public void addMapElement(Field field)
 	{
+		field.addProperyChangeListener(this);
 		map.add(field);
 	}
 
@@ -136,6 +148,21 @@ public class Model
 		}
 		return true;
 	}
+	
+	public boolean openWormhole(Portal portal)
+	{
+		int i = 0;
+		while(i<map.size())
+		{
+			if(map.get(i).openWormhole(portal))
+			{
+				return true;
+			}
+			i++;
+		}
+		
+		return false;
+	}
 
 	public void setSpecOpenNum(int num)
 	{
@@ -158,10 +185,6 @@ public class Model
 		return replicator;
 	}
 
-	/*public void setMainGate(Gate mainGate) {
-		this.mainGate = mainGate;
-	}*/
-
 	public int getSpecOpen()
 	{
 		return this.specOpen;
@@ -180,4 +203,25 @@ public class Model
 	{
 		return this.isMapFinished;
 	}
+
+	@Override
+	public void propertyChange(PropertyChangeEvent evt)
+	{
+		int place = findField((Field)evt.getNewValue());
+		if(place < 0 || place >= map.size())
+		{
+			//propSupp.firePropertyChange("error", null, null);
+			System.err.println("changed field not found");
+		}
+		else
+		{
+			propSupp.firePropertyChange("change", evt.getNewValue(), place);
+		}
+	}
+	
+	private int findField(Field field)
+	{
+		return map.indexOf(field);
+		
+	}
 }
\ No newline at end of file
diff --git a/core/mapobjs/defobjs/Door.java b/core/mapobjs/defobjs/Door.java
index 863df7f..8093101 100644
--- a/core/mapobjs/defobjs/Door.java
+++ b/core/mapobjs/defobjs/Door.java
@@ -24,7 +24,7 @@ public class Door extends DefaultElement implements IElement{
 			return true;
 		}
 
-}
+	}
 
 	@Override
 	public boolean meet(Replicator replicator) {
@@ -38,6 +38,7 @@ public class Door extends DefaultElement implements IElement{
 		}
 	}
 
+	@Override
 	public boolean meet(Player colonel)
 	{
 		if(isOpen == false)
@@ -50,9 +51,16 @@ public class Door extends DefaultElement implements IElement{
 		}
 	}
 
+	@Override
+	public boolean leave(Player player)
+	{
+		return true;
+	}
+
 	public void setOpen(boolean isOpen)
 	{
 		this.isOpen=isOpen;
+	    this.getField().iChangedMyState();
 	}
 
 }
diff --git a/core/mapobjs/defobjs/Field.java b/core/mapobjs/defobjs/Field.java
index 7460db2..71f83db 100644
--- a/core/mapobjs/defobjs/Field.java
+++ b/core/mapobjs/defobjs/Field.java
@@ -1,5 +1,7 @@
 package mapobjs.defobjs;
 
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 
 import exceptions.DamagedException;
@@ -9,12 +11,21 @@ import mapobjs.movobjs.Player;
 import mapobjs.movobjs.Replicator;
 
 public class Field implements IElement {
-
+	private final PropertyChangeSupport propSupp = new PropertyChangeSupport(this);
+	
 	private ArrayList<DefaultElement> toRemove = new ArrayList<>();
-	private ArrayList<DefaultElement> elements = new ArrayList<DefaultElement>();
+	private ArrayList<DefaultElement> toInsert = new ArrayList<>();
+	private ArrayList<DefaultElement> elements = new ArrayList<>();
 	public  Field[] neighbours = new  Field[4];
 
-	public Field() {
+	public Field() { }
+	
+	public void addProperyChangeListener(PropertyChangeListener listener)
+	{
+		if(listener != null)
+		{
+			propSupp.addPropertyChangeListener(listener);
+		}
 	}
 
 	public boolean addElement (DefaultElement elem){
@@ -42,7 +53,8 @@ public class Field implements IElement {
 		}
 	}
 
-	public Field getNeighbour(Direction dir){
+	public Field getNeighbour(Direction dir)
+	{
 		switch (dir) {
         case UP:
             return neighbours[0];
@@ -55,8 +67,8 @@ public class Field implements IElement {
         default:
             return null;
 		}
-
 	}
+	
 	@Override
 	public boolean meet(Player colonel) {
 		boolean isValid = true;
@@ -74,22 +86,14 @@ public class Field implements IElement {
 			}
 
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
 		if(isValid)
 		{
-			this.elements.add(colonel);
+			addToInsert(colonel);
 		}
 		
+		insertInsertables();
+		removeRemovables();
+		
 		return isValid;
 	}
 
@@ -102,17 +106,9 @@ public class Field implements IElement {
 			}
 
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
+		
+		insertInsertables();
+		removeRemovables();
 		/*
 		 * No need to add bullet to the list of elements,
 		 * because it moves through the field in atomic time.
@@ -143,18 +139,10 @@ public class Field implements IElement {
 				return true;
 			}
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
-		this.elements.add(box);
+		addToInsert(box);
+		
+		insertInsertables();
+		removeRemovables();
 		return true;
 	}
 
@@ -166,24 +154,14 @@ public class Field implements IElement {
 				isValid = false;
 			}
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
 		if(isValid)
 		{
-			this.elements.remove(colonel);
-			return true;
+			addToRemove(colonel);
 		}
-		else
-			return false;
+		
+		removeRemovables();
+		
+		return isValid;
 	}
 
 	@Override
@@ -195,26 +173,14 @@ public class Field implements IElement {
 				tmp = box;
 			}
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
 		if(tmp != null)
 		{
-			this.elements.remove(tmp);
-			return tmp;
-		}
-		else
-		{
-			return null;
+			addToRemove(tmp);
 		}
+		
+		removeRemovables();
+		
+		return tmp;
 	}
 
 	public boolean leave(Portal portal) {
@@ -225,23 +191,14 @@ public class Field implements IElement {
 				break;
 			}
 		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
-			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
-			}
-			toRemove.clear();
-		}
 		if(tmp != null)
 		{
-			this.elements.remove(tmp);
-			return true;
+			addToRemove(tmp);
 		}
-		return false;
+		
+		removeRemovables();
+		
+		return tmp!=null ? true : false;	// if tmp != null then return true, other cases return false
 	}
 
 
@@ -249,7 +206,10 @@ public class Field implements IElement {
 	public void damaged() {}
 
 	public boolean leave(Replicator replicator) {
-		this.elements.remove(replicator);
+		addToRemove(replicator);
+		
+		removeRemovables();
+		
 		return true;
 	}
 
@@ -264,25 +224,17 @@ public class Field implements IElement {
 		}
 		if(isValid)
 		{
-			this.elements.add(replicator);
+			addToInsert(replicator);
 			
-			if(toRemove.size() == 1)	// TODO: bűn ronda, és hibához vezethet
-			{
-				toRemove.add(replicator);
-			}
-		}
-		if(!toRemove.isEmpty())
-		{
-			for(DefaultElement toRemElement : toRemove)
+			if(toRemove.size() == 2)	// TODO: bűn ronda, és hibához vezethet
 			{
-				if(elements.contains(toRemElement))
-				{
-					elements.remove(toRemElement);
-				}
+				addToRemove(replicator);
 			}
-			toRemove.clear();
 		}
 		
+		insertInsertables();
+		removeRemovables();
+		
 		return isValid;
 	}
 
@@ -308,8 +260,86 @@ public class Field implements IElement {
 		toRemove.add(element);
 	}
 	
+	public void addToInsert(DefaultElement element)
+	{
+		toInsert.add(element);
+	}
+	
+	private void insertInsertables()
+	{
+		if(!toInsert.isEmpty())
+		{
+			boolean anyChanged = false;
+			for(DefaultElement toInsElement : toInsert)
+			{
+				if(!elements.contains(toInsElement))
+				{
+					elements.add(toInsElement);
+					anyChanged = true;
+				}
+			}
+			toInsert.clear();
+			
+			if(anyChanged)
+			{
+				propSupp.firePropertyChange("insert", null, this);
+			}
+		}
+	}
+	
+	private void removeRemovables()
+	{
+		if(!toRemove.isEmpty())
+		{
+			boolean anyChanged = false;
+			for(DefaultElement toRemElement : toRemove)
+			{
+				if(elements.contains(toRemElement))
+				{
+					elements.remove(toRemElement);
+					anyChanged = true;
+				}
+			}
+			toRemove.clear();
+			
+			if(anyChanged)
+			{
+				propSupp.firePropertyChange("remove", null, this);
+			}
+		}
+	}
+	
+	public void iChangedMyState()
+	{
+		propSupp.firePropertyChange("playerChanged", null, this);
+	}
+	
 	public boolean hasElementOn()
 	{
 		return !elements.isEmpty();
 	}
+	
+	public int getElementNum()
+	{
+		return elements.size();
+	}
+	
+	public DefaultElement getElement(int index)
+	{
+		return elements.get(index);
+	}
+	
+	public boolean openWormhole(Portal portal)
+	{
+		for (DefaultElement defElement : elements) {
+			if(defElement instanceof Portal)	// TODO: más megoldás
+			{
+				Portal ownPortal = (Portal)defElement;
+				
+				return ownPortal.setOtherSide(portal, false);	// return true if success, false if portals are not from same player
+			}
+		}
+		
+		return false;
+	}
 }
diff --git a/core/mapobjs/defobjs/Portal.java b/core/mapobjs/defobjs/Portal.java
index 75e2f6d..c9677f8 100644
--- a/core/mapobjs/defobjs/Portal.java
+++ b/core/mapobjs/defobjs/Portal.java
@@ -2,7 +2,6 @@ package mapobjs.defobjs;
 
 import game.Direction;
 import game.PortalColor;
-import mapobjs.movobjs.Player;
 import mapobjs.movobjs.Replicator;
 
 /**
@@ -14,25 +13,37 @@ import mapobjs.movobjs.Replicator;
  * @author Temesvári Fanni
  */
 public class Portal extends DefaultElement {
-	/*
-	 * Color is not used.
-	 * Is this attribute useful?
-	 * TODO getter
-	 */
 	private PortalColor color;
 	private Direction side;
 	private Portal otherSide = null;
 
-	public void setOtherSide(Portal otherSide) {
-		this.otherSide = otherSide;
+	public void setOtherSide()
+	{
+		this.getField().getNeighbour(side).setNeighbour(Direction.convertToInverse(side), this.getField());
+		otherSide.getField().getNeighbour(otherSide.side).setNeighbour(Direction.convertToInverse(otherSide.side), otherSide.getField());
 	}
-
-	// TODO is it possible to create a portal without color?
-	public Portal(Field ownField){
-		super(ownField);
+	
+	public boolean setOtherSide(Portal otherSide, boolean isSecondTurn) {
+		if(isSecondTurn)
+		{
+			this.otherSide = otherSide;
+			this.getField().getNeighbour(side).setNeighbour(Direction.convertToInverse(side), this.getOtherSideField());
+			otherSide.getField().getNeighbour(otherSide.side)
+				.setNeighbour(Direction.convertToInverse(otherSide.side), otherSide.getOtherSideField());
+			return true;
+		}
+		
+		if(PortalColor.convertToInverse(otherSide.getColor()).equals(this.color))
+		{
+			this.otherSide = otherSide;
+			otherSide.setOtherSide(this, true);
+			
+			return true;
+		}
+		
+		return false;
 	}
 
-	// TODO is it useful to create a portal without direction?
 	public Portal(Field ownField, PortalColor color) {
 		super(ownField);
 		this.color = color;
@@ -44,16 +55,6 @@ public class Portal extends DefaultElement {
 		this.side = side;
 	}
 
-	@Override
-	public boolean meet(Player colonel){
-		if(otherSide == null) {
-			colonel.damaged();
-		}else{
-			return this.otherSide.getField().getNeighbour(otherSide.side).meet(colonel);
-		}
-		return true;
-	}
-
 	@Override
 	public boolean meet(Replicator replicator){
 		if(otherSide == null) {
@@ -67,12 +68,9 @@ public class Portal extends DefaultElement {
 	@Override
 	public void damaged(){
 		this.getField().addToRemove(this);
-		//this.getField().deleteElement(this);
-		//this.setField(null);
 	}
-
-	// TODO I assume getSide() instead of side()
-	public Direction side()
+	
+	public Direction getSide()
 	{
 		return side;
 	}
@@ -81,8 +79,6 @@ public class Portal extends DefaultElement {
 	public boolean leave(Portal portal) {
 		if(portal.equals(this)) {
 			this.getField().addToRemove(this);
-			//this.getField().deleteElement(this);
-			//this.setField(null);
 			return true;
 		}else {
 			return false;
@@ -108,4 +104,14 @@ public class Portal extends DefaultElement {
 
 		return false;
 	}
+	
+	public PortalColor getColor()
+	{
+		return this.color;
+	}
+	
+	public Field getOtherSideField()
+	{
+		return otherSide.getField().getNeighbour(otherSide.side);
+	}
 }
diff --git a/core/mapobjs/defobjs/Ravine.java b/core/mapobjs/defobjs/Ravine.java
index d452034..df263a4 100644
--- a/core/mapobjs/defobjs/Ravine.java
+++ b/core/mapobjs/defobjs/Ravine.java
@@ -35,7 +35,6 @@ public class Ravine extends DefaultElement {
 	public boolean meet(Replicator replicator) {
 		replicator.damaged();
 		this.getField().addToRemove(this);
-		//this.getField().deleteElement(this);
 		return true;
 	}
 }
\ No newline at end of file
diff --git a/core/mapobjs/defobjs/Wall.java b/core/mapobjs/defobjs/Wall.java
index fc55030..06206fd 100644
--- a/core/mapobjs/defobjs/Wall.java
+++ b/core/mapobjs/defobjs/Wall.java
@@ -2,6 +2,7 @@ package mapobjs.defobjs;
 
 
 import game.Direction;
+import game.Model;
 import mapobjs.movobjs.*;
 
 public class Wall extends DefaultElement{
@@ -55,7 +56,8 @@ public class Wall extends DefaultElement{
         		portals[3] = portal;
         		break;
         	}
-            this.getField().addElement(portal);
+            this.getField().addToInsert(portal);
+        	Model.getInstance().openWormhole(portal);
         }
         return false;
     }
@@ -72,9 +74,15 @@ public class Wall extends DefaultElement{
     		return false;
     	for (Portal myportal : this.portals) {
     		if(portal.equals(myportal)) {
+    			closeWormhole(myportal);
     			myportal = null;
     		}
     	}
         return false;
     }
+    
+    private void closeWormhole(Portal portal)
+    {
+    	portal.setOtherSide();
+    }
 }
diff --git a/core/mapobjs/movobjs/Player.java b/core/mapobjs/movobjs/Player.java
index ed2841b..d38ecc0 100644
--- a/core/mapobjs/movobjs/Player.java
+++ b/core/mapobjs/movobjs/Player.java
@@ -70,7 +70,7 @@ public class Player extends DefaultElement implements IMovable {
     	{
     		if(originField.meet(this))
     		{
-        		this.getField().leave(this);
+        		this.getField().addToRemove(this);
         		this.setField(originField);
     		}
     	}
@@ -78,16 +78,17 @@ public class Player extends DefaultElement implements IMovable {
 
     @Override
     public boolean step() {
-       Field nextField = this.getField().getNeighbour(dir);
-       boolean success = nextField.meet(this);
-       if(success)
+    	Field nextField = this.getField().getNeighbour(dir);
+    	boolean success = nextField.meet(this);
+    	if(success)
    		{
-    	   this.getField().leave(this);
-    	   this.setField(nextField);
-    	   return true;
+    		this.getField().leave(this);
+    		this.setField(nextField);
+    		return true;
    		}
-       return false;
+    	return false;
     }
+    
     public boolean getBoxUp()
     {
     	// cannot take more boxes
@@ -96,29 +97,41 @@ public class Player extends DefaultElement implements IMovable {
     	Field newField = this.getField().getNeighbour(dir);
     	Box box = newField.leave();
     	if(box == null)
+    	{
     		return false;
+    	}
+    	
     	box.setField(null);
     	this.box = box;
+	    this.getField().iChangedMyState();
+	    
         return true;
     }
+    
     public boolean putBoxDown()
     {
     	if(this.box == null)
     		return false;
     	Field newField = this.getField().getNeighbour(dir);
     	boolean success = newField.meet(this.box);
-    	 if(success) {
-    		 this.box = null;
-    		 return true;
-    		}
+    	if(success)
+    	{
+    		this.box = null;
+    	    this.getField().iChangedMyState();
+    	    
+    		return true;
+    	}
+    	
         return false;
     }
+    
     public boolean fire(PortalColor color)
     {
 		Model.getInstance().portalClose(new Portal(null, color));
 		Bullet bullet = new Bullet(this.getField(), color, this.dir);
         return bullet.step();
     }
+    
     public Direction getDirection()
     {
         return this.dir;
@@ -145,6 +158,7 @@ public class Player extends DefaultElement implements IMovable {
     public void setDirection(Direction dir)
     {
     	this.dir = dir;
+    	this.getField().iChangedMyState();
     }
 
 	public void setPlayerLives(int playerLives) {
diff --git a/core/mapobjs/movobjs/Replicator.java b/core/mapobjs/movobjs/Replicator.java
index f53329d..f86c0bb 100644
--- a/core/mapobjs/movobjs/Replicator.java
+++ b/core/mapobjs/movobjs/Replicator.java
@@ -1,6 +1,7 @@
 package mapobjs.movobjs;
 
 import game.Direction;
+import game.Model;
 import mapobjs.defobjs.Box;
 import mapobjs.defobjs.DefaultElement;
 import mapobjs.defobjs.Field;
@@ -16,16 +17,17 @@ public class Replicator extends DefaultElement implements IMovable {
 	public boolean meet(Player colonel) {
 		return true;
 	}
+
 	@Override
-	public boolean meet(Box box) {
-		return false;
+	public boolean leave(Player player)
+	{
+		return true;
 	}
 
 	@Override
 	public void damaged() {
-		this.getField().addToRemove(this);
-		//this.getField().deleteElement(this);
-		//this.setField(null);
+		this.getField().getNeighbour(dir).addToRemove(this);
+		Model.getInstance().setReplicator(null);
 	}
 
 	@Override
@@ -54,6 +56,7 @@ public class Replicator extends DefaultElement implements IMovable {
 	public void setDirection(Direction dir)
 	{
 		this.dir = dir;
+		this.getField().iChangedMyState();
 	}
 
 }
diff --git a/core/maps/testmap.txt b/core/maps/testmap.txt
index 149c4e9..f434365 100644
--- a/core/maps/testmap.txt
+++ b/core/maps/testmap.txt
@@ -2,8 +2,17 @@ create map 10 10
 create colonel 1 1
 create gate 2 3
 create ra 0 0
-create re 5 5
 create jaffa 1 0
 create door 2 2 3 3
 create box 3 2
-create zpm 2 0
\ No newline at end of file
+create zpm 2 0
+create wall 5 0
+create wall 5 1
+create wall 5 2
+create wall 5 3
+create wall 5 4
+create wall 5 5
+create wall 0 5
+create wall 1 5
+create wall 2 5
+create wall 3 5
\ No newline at end of file
-- 
GitLab