1 /***************************************************************************
2  *                 (C) Copyright 2003-2015 - Faiumoni e.V.                 *
3  ***************************************************************************
4  ***************************************************************************
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  ***************************************************************************/
12 package games.stendhal.server.script;
13 
14 import java.io.IOException;
15 import java.util.List;
16 
17 import games.stendhal.common.tiled.LayerDefinition;
18 import games.stendhal.common.tiled.StendhalMapStructure;
19 import games.stendhal.server.core.config.zone.TMXLoader;
20 import games.stendhal.server.core.engine.SingletonRepository;
21 import games.stendhal.server.core.engine.StendhalRPWorld;
22 import games.stendhal.server.core.engine.StendhalRPZone;
23 import games.stendhal.server.core.scripting.ScriptImpl;
24 import games.stendhal.server.entity.player.Player;
25 import marauroa.common.game.IRPZone;
26 
27 /**
28  * Replaces a map's data with that loaded from a .tmx.
29  */
30 public class ChangeMap extends ScriptImpl {
31 	@Override
execute(final Player admin, final List<String> args)32 	public void execute(final Player admin, final List<String> args) {
33 		final StendhalRPWorld world = SingletonRepository.getRPWorld();
34 		if (args.size() != 2) {
35 			sandbox.privateText(admin, "Usage: /script modified_zone path_to_tmx");
36 			return;
37 		}
38 		IRPZone zn = world.getRPZone(args.get(0));
39 		if (!(zn instanceof StendhalRPZone)) {
40 			sandbox.privateText(admin, "Zone not found: '" + args.get(1) + "'");
41 			return;
42 		}
43 		StendhalRPZone zone = (StendhalRPZone) zn;
44 		StendhalMapStructure map;
45 		try {
46 			map = TMXLoader.load(args.get(1));
47 		} catch (Exception e) {
48 			sandbox.privateText(admin, "Failed to load map: " + e);
49 			return;
50 		}
51 		try {
52 			updateZone(zone, map);
53 			zone.notifyOnlinePlayers();
54 		} catch (IOException e) {
55 			sandbox.privateText(admin, "Failed to update map: " + e);
56 		}
57 	}
58 
59 	/**
60 	 * Update zone from StendhalMapStructure.
61 	 *
62 	 * @param zone zone to be updated
63 	 * @param map new map data
64 	 * @throws IOException When encoding the layer data fails
65 	 */
updateZone(StendhalRPZone zone, StendhalMapStructure map)66 	private void updateZone(StendhalRPZone zone, StendhalMapStructure map) throws IOException {
67 		// FIXME: Add some safety checking. As of now the script allows
68 		// replacing any zone with any tmx, whether the size or collisions match.
69 		String name = zone.getName();
70 		zone.addTilesets(name + ".tilesets", map.getTilesets());
71 		zone.addLayer(name + ".0_floor", map.getLayer("0_floor"));
72 		zone.addLayer(name + ".1_terrain", map.getLayer("1_terrain"));
73 		zone.addLayer(name + ".2_object", map.getLayer("2_object"));
74 
75 		// Roof layers are optional
76 		loadOptionalLayer(zone, map, "3_roof");
77 		loadOptionalLayer(zone, map, "4_roof_add");
78 		// Effect layers are optional too
79 		loadOptionalLayer(zone, map, "blend_ground");
80 		loadOptionalLayer(zone, map, "blend_roof");
81 
82 		zone.addCollisionLayer(name + ".collision", map.getLayer("collision"));
83 		zone.addProtectionLayer(name + ".protection", map.getLayer("protection"));
84 		// FIXME: Should old spawn points be kept, or change those too?
85 		// Currently they are kept.
86 	}
87 
88 	/**
89 	 * Load an optional layer, if present, to a zone.
90 	 *
91 	 * @param zone zone to be updated
92 	 * @param zonedata new map data
93 	 * @param layerName name of the layer
94 	 * @throws IOException When encoding the layer data fails
95 	 */
loadOptionalLayer(StendhalRPZone zone, StendhalMapStructure zonedata, String layerName)96 	private void loadOptionalLayer(StendhalRPZone zone,
97 			StendhalMapStructure zonedata, String layerName) throws IOException {
98 		LayerDefinition layer = zonedata.getLayer(layerName);
99 		if (layer != null) {
100 			zone.addLayer(zone.getName() + "." + layerName, layer);
101 		}
102 	}
103 }
104