001/* 002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games. 003 * Copyright (C) 2000-2010 The Gridarta Developers. 004 * 005 * This program is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation; either version 2 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License along 016 * with this program; if not, write to the Free Software Foundation, Inc., 017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 018 */ 019 020package net.sf.gridarta.model.mapmodel; 021 022import java.awt.Point; 023import java.util.regex.Pattern; 024import net.sf.gridarta.model.anim.AnimationObjects; 025import net.sf.gridarta.model.archetype.DuplicateArchetypeException; 026import net.sf.gridarta.model.archetype.TestArchetype; 027import net.sf.gridarta.model.archetype.TestDefaultArchetype; 028import net.sf.gridarta.model.archetypeset.ArchetypeSet; 029import net.sf.gridarta.model.baseobject.BaseObject; 030import net.sf.gridarta.model.baseobject.GameObjectContainer; 031import net.sf.gridarta.model.face.FaceObjectProviders; 032import net.sf.gridarta.model.gameobject.GameObject; 033import net.sf.gridarta.model.gameobject.GameObjectFactory; 034import net.sf.gridarta.model.gameobject.TestGameObject; 035import net.sf.gridarta.model.maparchobject.TestMapArchObject; 036import net.sf.gridarta.utils.Size2D; 037import net.sf.gridarta.utils.StringUtils; 038import org.jetbrains.annotations.NotNull; 039import org.junit.Assert; 040 041/** 042 * Helper class for creating {@link MapModel} instances for regression tests. 043 * @author Andreas Kirschbaum 044 */ 045public class TestMapModelHelper { 046 047 /** 048 * The archetype type used for "exit" game objects. 049 */ 050 public static final int EXIT_TYPE = 1; 051 052 /** 053 * The archetype type used for "floor" game objects. 054 */ 055 private static final int FLOOR_TYPE = 2; 056 057 /** 058 * The archetype type used for "mob" game objects. 059 */ 060 private static final int MOB_TYPE = 3; 061 062 /** 063 * An empty array of strings. 064 */ 065 @NotNull 066 private static final String[] EMPTY_STRING_ARRAY = new String[0]; 067 068 /** 069 * The "topmost" {@link InsertionMode} instance. 070 */ 071 @NotNull 072 private final InsertionMode<TestGameObject, TestMapArchObject, TestArchetype> topmostInsertionMode; 073 074 /** 075 * The {@link GameObjectFactory} instance. 076 */ 077 @NotNull 078 private final GameObjectFactory<TestGameObject, TestMapArchObject, TestArchetype> gameObjectFactory; 079 080 /** 081 * The archetype to create floor game objects. 082 */ 083 @NotNull 084 private final TestArchetype floorArchetype; 085 086 /** 087 * The archetype to create exit game objects. 088 */ 089 @NotNull 090 private final TestArchetype exitArchetype; 091 092 /** 093 * The archetype to create 2x1 mob game objects. 094 */ 095 @NotNull 096 private final TestArchetype mob21Archetype; 097 098 /** 099 * Creates a new instance. 100 * @param topmostInsertionMode the "topmost" insertion mode instance 101 * @param gameObjectFactory the game object factory to use 102 * @param archetypeSet the archetype set to use 103 * @param faceObjectProviders the face object providers to use 104 * @param animationObjects the animation objects to use 105 * @throws DuplicateArchetypeException if an internal error occurs 106 */ 107 public TestMapModelHelper(@NotNull final InsertionMode<TestGameObject, TestMapArchObject, TestArchetype> topmostInsertionMode, @NotNull final GameObjectFactory<TestGameObject, TestMapArchObject, TestArchetype> gameObjectFactory, @NotNull final ArchetypeSet<TestGameObject, TestMapArchObject, TestArchetype> archetypeSet, @NotNull final FaceObjectProviders faceObjectProviders, @NotNull final AnimationObjects animationObjects) throws DuplicateArchetypeException { 108 this.topmostInsertionMode = topmostInsertionMode; 109 this.gameObjectFactory = gameObjectFactory; 110 111 floorArchetype = new TestDefaultArchetype("floor", faceObjectProviders, animationObjects); 112 floorArchetype.setAttributeInt(BaseObject.TYPE, FLOOR_TYPE); 113 archetypeSet.addArchetype(floorArchetype); 114 115 exitArchetype = new TestDefaultArchetype("exit", faceObjectProviders, animationObjects); 116 exitArchetype.setAttributeInt(BaseObject.TYPE, EXIT_TYPE); 117 archetypeSet.addArchetype(exitArchetype); 118 119 mob21Archetype = new TestDefaultArchetype("mob21", faceObjectProviders, animationObjects); 120 mob21Archetype.setAttributeInt(BaseObject.TYPE, MOB_TYPE); 121 archetypeSet.addArchetype(mob21Archetype); 122 final TestArchetype mob21bArchetype = new TestDefaultArchetype("mob21b", faceObjectProviders, animationObjects); 123 mob21bArchetype.setMultiX(1); 124 mob21Archetype.addTailPart(mob21bArchetype); 125 archetypeSet.addArchetype(mob21bArchetype); 126 } 127 128 /** 129 * Inserts a {@link #floorArchetype} game object into a map model. 130 * @param mapModel the map model to insert into 131 * @param point the position to insert at 132 * @return the inserted game object 133 * @throws CannotInsertGameObjectException if the archetype cannot be 134 * inserted 135 */ 136 @NotNull 137 public TestGameObject insertFloor(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final Point point) throws CannotInsertGameObjectException { 138 return insertArchetype(mapModel, point, floorArchetype, false); 139 } 140 141 /** 142 * Inserts an {@link #exitArchetype} game object into a map model. 143 * @param mapModel the map model to insert into 144 * @param point the position to insert at 145 * @return the inserted game object 146 * @throws CannotInsertGameObjectException if the archetype cannot be 147 * inserted 148 */ 149 @NotNull 150 public TestGameObject insertExit(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final Point point) throws CannotInsertGameObjectException { 151 return insertArchetype(mapModel, point, exitArchetype, false); 152 } 153 154 /** 155 * Inserts a {@link #mob21Archetype} game object into a map model. 156 * @param mapModel the map model to insert into 157 * @param point the position to insert at 158 * @return the inserted game object 159 * @throws CannotInsertGameObjectException if the archetype cannot be 160 * inserted 161 */ 162 @NotNull 163 public TestGameObject insertMob21(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final Point point) throws CannotInsertGameObjectException { 164 return insertArchetype(mapModel, point, mob21Archetype, false); 165 } 166 167 /** 168 * Inserts an archetype game object into a map model. 169 * @param mapModel the map model to insert into 170 * @param x the x coordinate to insert at 171 * @param y the y coordinate to insert at 172 * @param archetype the archetype to insert 173 * @param join whether to perform autojoining 174 * @return the inserted game object 175 * @throws CannotInsertGameObjectException if the archetype cannot be 176 * inserted 177 */ 178 @NotNull 179 public TestGameObject insertArchetype(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, final int x, final int y, @NotNull final BaseObject<TestGameObject, TestMapArchObject, TestArchetype, ?> archetype, final boolean join) throws CannotInsertGameObjectException { 180 return insertArchetype(mapModel, new Point(x, y), archetype, join); 181 } 182 183 /** 184 * Inserts an archetype game object into a map model. 185 * @param mapModel the map model to insert into 186 * @param point the position to insert at 187 * @param archetype the archetype to insert 188 * @param join whether to perform autojoining 189 * @return the inserted game object 190 * @throws CannotInsertGameObjectException if the archetype cannot be 191 * inserted 192 */ 193 @NotNull 194 public TestGameObject insertArchetype(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final Point point, @NotNull final BaseObject<TestGameObject, TestMapArchObject, TestArchetype, ?> archetype, final boolean join) throws CannotInsertGameObjectException { 195 final TestGameObject gameObject = mapModel.insertBaseObject(archetype, point, true, join, topmostInsertionMode); 196 if (gameObject == null) { 197 throw new CannotInsertGameObjectException(archetype, point); 198 } 199 return gameObject; 200 } 201 202 /** 203 * Inserts an {@link #exitArchetype} game object into a game object. 204 * @param gameObject the game object 205 * @return the inserted game object 206 */ 207 @NotNull 208 public TestGameObject insertExit(@NotNull final GameObjectContainer<TestGameObject, TestMapArchObject, TestArchetype> gameObject) { 209 return insertArchetype(gameObject, exitArchetype); 210 } 211 212 /** 213 * Inserts a {@link #mob21Archetype} game object into a game object. 214 * @param gameObject the game object 215 * @return the inserted game object 216 */ 217 @NotNull 218 public TestGameObject insertMob21(@NotNull final GameObjectContainer<TestGameObject, TestMapArchObject, TestArchetype> gameObject) { 219 return insertArchetype(gameObject, mob21Archetype); 220 } 221 222 /** 223 * Inserts an archetype into a game object. 224 * @param gameObject the game object 225 * @param archetype the archetype to insert 226 * @return the inserted game object 227 */ 228 @NotNull 229 public TestGameObject insertArchetype(@NotNull final GameObjectContainer<TestGameObject, TestMapArchObject, TestArchetype> gameObject, @NotNull final BaseObject<TestGameObject, TestMapArchObject, TestArchetype, ?> archetype) { 230 final TestGameObject newGameObject = archetype.newInstance(gameObjectFactory); 231 gameObject.addLast(newGameObject); 232 return newGameObject; 233 } 234 235 /** 236 * Checks for expected {@link MapModel}'s contents. 237 * @param mapModel the map model 238 * @param lines the expected contents 239 */ 240 public static void checkMapContents(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final String... lines) { 241 final Size2D mapSize = mapModel.getMapArchObject().getMapSize(); 242 Assert.assertEquals(lines.length, mapSize.getHeight()); 243 final Pattern pattern1 = Pattern.compile("\\|"); 244 final Pattern pattern2 = StringUtils.PATTERN_COMMA; 245 final Point pos = new Point(); 246 for (int y = 0; y < lines.length; y++) { 247 final CharSequence line = lines[y]; 248 final String[] square = pattern1.split(line, -1); 249 Assert.assertEquals(square.length, mapSize.getWidth()); 250 251 for (int x = 0; x < square.length; x++) { 252 final String square2 = square[x]; 253 final String[] gameObjects = square2.isEmpty() ? EMPTY_STRING_ARRAY : pattern2.split(square2, -1); 254 pos.x = x; 255 pos.y = y; 256 checkContentsString(mapModel.getMapSquare(pos), gameObjects); 257 } 258 } 259 } 260 261 /** 262 * Checks that a {@link MapSquare} contains the given game objects. 263 * @param mapSquare the map square 264 * @param gameObjects the game object 265 */ 266 private static void checkContentsString(@NotNull final MapSquare<TestGameObject, TestMapArchObject, TestArchetype> mapSquare, @NotNull final String... gameObjects) { 267 int i = 0; 268 for (final BaseObject<?, ?, ?, ?> gameObject : mapSquare) { 269 final String gameObjectName = gameObject.getBestName(); 270 if (i >= gameObjects.length) { 271 Assert.fail("map square " + mapSquare.getMapX() + "/" + mapSquare.getMapY() + " contains excess game object '" + gameObjectName + "'"); 272 } else if (!gameObjectName.equals(gameObjects[i])) { 273 Assert.fail("map square " + mapSquare.getMapX() + "/" + mapSquare.getMapY() + " contains wrong game object '" + gameObjectName + "' at index " + i + ", expected '" + gameObjects[i] + "'"); 274 } 275 i++; 276 } 277 if (i < gameObjects.length) { 278 Assert.fail("map square " + mapSquare.getMapX() + "/" + mapSquare.getMapY() + " is missing game object '" + gameObjects[i] + "'"); 279 } 280 } 281 282 /** 283 * Checks that a {@link MapSquare} contains the given game objects. 284 * @param mapSquare the map square 285 * @param gameObjects the game object 286 */ 287 public static void checkContents(@NotNull final Iterable<TestGameObject> mapSquare, @NotNull final BaseObject<?, ?, ?, ?>... gameObjects) { 288 int i = 0; 289 for (final BaseObject<?, ?, ?, ?> gameObject : mapSquare) { 290 final String gameObjectName = gameObject.getBestName(); 291 if (i >= gameObjects.length) { 292 Assert.fail("map square contains excess game object '" + gameObjectName + "'"); 293 } else if (gameObject != gameObjects[i]) { 294 Assert.fail("map square contains wrong game object '" + gameObjectName + "' at index " + i + ", expected '" + gameObjects[i].getBestName() + "'"); 295 } 296 i++; 297 } 298 if (i < gameObjects.length) { 299 Assert.fail("map square is missing game object '" + gameObjects[i].getBestName() + "'"); 300 } 301 302 final boolean inContainer = mapSquare instanceof GameObject; 303 for (final GameObject<?, ?, ?> gameObject : mapSquare) { 304 Assert.assertEquals(inContainer, gameObject.isInContainer()); 305 if (inContainer) { 306 // game objects within inventories must not contain tail parts 307 Assert.assertFalse(gameObject.isMulti()); 308 } else { 309 // game objects on the map must have expanded tail parts 310 Assert.assertEquals(gameObject.getArchetype().isMulti(), gameObject.isMulti()); 311 } 312 } 313 } 314 315}