gt:                     if (!door.getOpenState()) {
context: package com.agorria.ouroboros.simulation.entity;
  
  import com.agorria.ouroboros.audio.SoundType;
  import com.agorria.ouroboros.core.Constants;
  import com.agorria.ouroboros.core.Utilities;
  import com.agorria.ouroboros.simulation.Simulation;
  import com.agorria.ouroboros.simulation.SimulationException;
  import com.agorria.ouroboros.simulation.enviroment.Buildable;
  import com.agorria.ouroboros.simulation.enviroment.EntityClass;
  import com.agorria.ouroboros.simulation.enviroment.EntityType;
  import com.agorria.ouroboros.simulation.enviroment.Node;
  import com.agorria.ouroboros.simulation.enviroment.Tile;
  import com.agorria.ouroboros.simulation.enviroment.World;
  import com.agorria.ouroboros.simulation.order.Order;
  import com.agorria.ouroboros.simulation.order.OrderBuild;
  import com.agorria.ouroboros.simulation.order.OrderDestruct;
  import com.agorria.ouroboros.simulation.order.OrderMove;
  import com.agorria.ouroboros.simulation.order.OrderStop;
  import org.joml.Vector2f;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Queue;
  import java.util.concurrent.ArrayBlockingQueue;
  
  
  /**
   * Created on 21/05/2017.
   * @author Ion Agorria
   *
   * Builds units
   * Factory must be updated after Units or spawn node will be free one step when transferring back to building
   */
  public class Factory extends Building {
      private static final long serialVersionUID = Utilities.getClassUID(Factory.class);
      private static final float EXIT_RADIUS = 3f;
      private static final Vector2f DOOR_POSITION = new Vector2f(0, 0.5f);
      private static final Vector2f SPAWN_POSITION = new Vector2f(0, 0f);
      public static final Vector2f EXIT_POSITION = new Vector2f(0, -1);
      private boolean isProducing;
      private FactoryState factoryState;
      private Unit produced;
      private FactoryDoor door;
      private Node spawn;
      private Node exit;
      /** Order queue for produced entities */
      private Queue<Order> producedOrders;
  
      public enum FactoryState {
          Idle,
          WaitDoorOpen,
          WaitExitFree,
          WaitExitMove,
          WaitDoorClose,
      }
  
      /** Used for unpacking entity */
      public Factory() {
          super(BuildingType.Factory);
          producedOrders = new ArrayBlockingQueue<>(Constants.QUEUE_ORDER_CAPACITY);
      }
  
      public Factory(Vector2f position) {
          super(BuildingType.Factory, position);
          factoryState = FactoryState.Idle;
          produced = null;
          isProducing = false;
          producedOrders = new ArrayBlockingQueue<>(Constants.QUEUE_ORDER_CAPACITY);
  
          //Add factory doors
          door = new FactoryDoor(getRectangle().getPosition(), getDirection());
          door.setParentOffset(DOOR_POSITION);
          addAttachedEntity(door);
      }
  
      @Override
      public void setSimulation(Simulation simulation) {
          super.setSimulation(simulation);
  
          if (spawn.getGroundEntity() != this) {
              throw new SimulationException("Spawn node doesn't belong to this factory");
          }
          if (exit.getGroundEntity() == this) {
              throw new SimulationException("Exit node is inside of factory");
          }
      }
  
      @Override
      public void readySimulation(Simulation simulation) {
          super.readySimulation(simulation);
  
          World world = simulation.getWorld();
          Vector2f position = getRectangle().getPosition();
          spawn = world.getNode(position.add(SPAWN_POSITION, new Vector2f()));
          exit = world.getNode(position.add(EXIT_POSITION, new Vector2f()));
  
          for (Entity entity : getAttachedEntities()) {
              if (entity.getEntityType() == EntityType.FactoryDoor) {
                  door = (FactoryDoor) entity;
                  break;
              }
          }
      }
  
      @Override
      public EntityClass getEntityClass() {
          return EntityClass.Factory;
      }
  
      @Override
      public void dispose() {
          if (produced != null) {
              //Destroy if inside factory
              if (factoryState == FactoryState.WaitDoorOpen) {
                  produced.setCurrentHealth(0);
              } else {
                  produced.setDisabled(false);
              }
              produced = null;
          }
          door = null;
          exit = null;
          super.dispose();
      }
  
      @Override
      public void update(float delta) {
          super.update(delta);
          updateProduced(delta);
  
          //Play audio if production state changed
          SoundType soundType = null;
          if (isProducing && getOrders().isEmpty()) {
              isProducing = false;
              if (produced != null) {
                  soundType = SoundType.ProductionCompleted;
              }
          } else if (!isProducing && !getOrders().isEmpty()) {
              isProducing = true;
              soundType = SoundType.ProductionStarted;
          }
          if (soundType != null) {
              getSimulation().addSoundSource(soundType, getRectangle().getPosition(), getPlayer());
          }
      }
  
      @Override
      public SoundType submitOrder(Order order) {
          //Check if order already had ID
          if (order.getID() != 0) {
              throw new SimulationException("Attempted to submit already submitted order " + order.toString());
          }
  
          //Don't submit if disabled, don't make any sound
          if (isDisabled()) {
              order.dispose();
              return null;
          }
  
          boolean added = false;
          boolean processed = false;
          if (order instanceof OrderBuild
           || order instanceof OrderDestruct) {
              return super.submitOrder(order);
          } else if (order instanceof OrderStop) {
              //Clear produced queue
              clearProducedOrders();
              processed = true;
          } else if (order.canQueue()) {
              //Offer to produced orders
              added = producedOrders.offer(order);
              processed = added;
          }
  
          //Dispose if not queued
          if (!added) {
              order.dispose();
          }
  
          //Produce feedback sound
          if (processed) {
              return SoundType.OrderReceived;
          } else {
              return SoundType.Buzzer;
          }
      }
  
      @Override
      public void clearOrders() {
          //Don't clear orders on factory, only produced orders
          clearProducedOrders();
      }
  
      /** Clears all produced orders in queue and disposes them */
      private void clearProducedOrders() {
          while (!producedOrders.isEmpty()) {
              Order order = producedOrders.poll();
              order.dispose();
          }
      }
  
      /** @return produced orders */
      public Queue<Order> getProducedOrders() {
          return producedOrders;
      }
  
      /**
       * Updates produced entity
       *
       * @param delta The time in seconds since the last update.
       */
      protected void updateProduced(float delta) {
          //If produced is dead remove state
          if (produced != null && produced.isDestroyed()) {
              produced = null;
          }
  
          //If produced is null set state to door close if not idle
          if (produced == null && factoryState != FactoryState.Idle) {
              factoryState = FactoryState.WaitDoorClose;
          }
  
          //Attempt to get spawn node if has no entity
          if (spawn.getGroundEntity() == null) {
              addNode(spawn);
          }
  
          //Check factory state
          switch (factoryState) {
              case Idle:
                  //Keep door closed
                  door.setOpenState(false);
                  break;
              case WaitDoorOpen:
                  //Wait until door is open
                  if (!door.isOpen()) {
  