diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/requests/RequestBuilder.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/requests/RequestBuilder.java
new file mode 100644
index 0000000..2297b76
--- /dev/null
+++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/requests/RequestBuilder.java
@@ -0,0 +1,139 @@
+package uulm.teamname.marvelous.gamelibrary.requests;
+
+import uulm.teamname.marvelous.gamelibrary.IntVector2;
+import uulm.teamname.marvelous.gamelibrary.entities.Entity;
+import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
+import uulm.teamname.marvelous.gamelibrary.entities.StoneType;
+
+import java.lang.reflect.Field;
+import java.util.StringJoiner;
+
+/**
+ * A class made for building all sorts of {@link Request}s as nicely as possible.
+ * It works by taking .with[KEY]() functions and then building a specific request at the end.
+ */
+public class RequestBuilder {
+ private RequestType type;
+
+ // Keys used primarily in GameRequests, but also in others
+ private EntityID targetEntity;
+ private IntVector2 targetField;
+ private Integer value;
+
+ // Keys used primarily in CharacterRequests
+ private EntityID originEntity;
+ private IntVector2 originField;
+ private StoneType stoneType;
+
+ /**
+ * Creates a new {@link RequestBuilder} used for building {@link Request}s.
+ * @param requestType is the type of Event that the final event will have
+ */
+ public RequestBuilder(RequestType requestType) {
+ this.type = requestType;
+ }
+
+ /**
+ * @deprecated Use {@link #RequestBuilder(RequestType)} instead.
+ */
+ @Deprecated
+ public RequestBuilder withType(RequestType type) {
+ this.type = type;
+ return this;
+ }
+
+ public RequestBuilder withTargetEntity(EntityID targetEntity) {
+ this.targetEntity = targetEntity;
+ return this;
+ }
+
+ public RequestBuilder withTargetField(IntVector2 targetField) {
+ this.targetField = targetField;
+ return this;
+ }
+
+ public RequestBuilder withValue(Integer value) {
+ this.value = value;
+ return this;
+ }
+
+ public RequestBuilder withOriginEntity(EntityID originEntity) {
+ this.originEntity = originEntity;
+ return this;
+ }
+
+ public RequestBuilder withOriginField(IntVector2 originField) {
+ this.originField = originField;
+ return this;
+ }
+
+ public RequestBuilder withStoneType(StoneType stoneType) {
+ this.stoneType = stoneType;
+ return this;
+ }
+
+ /**
+ * Builds a {@link GameRequest} from the values given to the builder.
+ *
+ * - type is the {@link RequestType} of the {@link GameRequest}.
+ *
+ *
+ * @return a {@link GameRequest} based on the builder
+ */
+ public GameRequest buildGameRequest() throws IllegalStateException {
+ var gameRequest = new GameRequest();
+ gameRequest.type = this.type;
+ return gameRequest;
+ }
+
+ /**
+ * Builds an {@link CharacterRequest} from the values given to the builder.
+ *
+ * - type is the {@link RequestType} of the EntityEvent
+ * - targetEntity is the target {@link Entity}
+ * - targetField is the target field in the form of an {@link IntVector2}
+ * - amount is a generic amount, for example damage taken
+ *
+ *
+ * @return an {@link CharacterRequest} based on the builder
+ */
+ public CharacterRequest buildCharacterRequest() throws IllegalStateException {
+ var characterRequest = new CharacterRequest();
+ characterRequest.type = this.type;
+ characterRequest.originEntity = this.originEntity;
+ characterRequest.originField = this.originField;
+ characterRequest.targetEntity = this.targetEntity;
+ characterRequest.targetField = this.targetField;
+ characterRequest.value = this.value;
+ characterRequest.stoneType = this.stoneType;
+ return characterRequest;
+ }
+
+ @Override
+ public String toString() {
+ StringJoiner joiner = new StringJoiner("\n");
+ joiner.add("RequestBuilder(all) {");
+ for(Field field: this.getClass().getDeclaredFields()) {
+ try {
+ joiner.add(field.getName() + " = " + field.get(this));
+ }catch(IllegalAccessException ignore) { }
+ }
+ joiner.add("}");
+ return joiner.toString();
+ }
+
+ public String notNullToString() {
+ StringJoiner joiner = new StringJoiner("\n");
+ joiner.add("RequestBuilder(non-null) {");
+ for(Field field: this.getClass().getDeclaredFields()) {
+ try {
+ Object value = field.get(this);
+ if(value != null) {
+ joiner.add(field.getName() + " = " + value);
+ }
+ }catch(IllegalAccessException ignore) { }
+ }
+ joiner.add("}");
+ return joiner.toString();
+ }
+}
diff --git a/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java b/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java
new file mode 100644
index 0000000..7c82d6f
--- /dev/null
+++ b/src/test/java/uulm/teamname/marvelous/gamelibrary/gamelogic/GameLogicTest.java
@@ -0,0 +1,42 @@
+package uulm.teamname.marvelous.gamelibrary.gamelogic;
+
+import org.junit.jupiter.api.Test;
+import uulm.teamname.marvelous.gamelibrary.IntVector2;
+import uulm.teamname.marvelous.gamelibrary.events.Event;
+import uulm.teamname.marvelous.gamelibrary.requests.RequestBuilder;
+import uulm.teamname.marvelous.gamelibrary.requests.RequestType;
+
+import java.util.ArrayList;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+class GameLogicTest {
+
+ @Test
+ void executeRequest() {
+ GameState state = new GameState(new IntVector2(10, 10));
+ //build a nice state (add entities and stuff)
+ ArrayList result = GameLogic.executeRequest(state, new RequestBuilder(RequestType.MeleeAttackRequest)
+ //build a nice request to check
+ //.withOriginEntity()
+ .buildCharacterRequest());
+ //check if result contains the right events
+ }
+
+ @Test
+ void buildGameStateEvent() {
+ }
+
+ @Test
+ void checkRequest() {
+ }
+
+ @Test
+ void applyEvent() {
+ }
+
+ @Test
+ void checkWinConditions() {
+ }
+}