package net.scapeemulator.game.model.player.skills.construction.room;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
import net.scapeemulator.game.model.Position;
import net.scapeemulator.game.model.object.GroundObjectList.GroundObject;
import net.scapeemulator.game.model.object.ObjectGroup;
import net.scapeemulator.game.model.player.RegionPalette;
import net.scapeemulator.game.model.player.RegionPalette.Tile;
import net.scapeemulator.game.model.player.RegionPalette.Tile.Rotation;
import net.scapeemulator.game.model.player.skills.construction.DoorType;
import net.scapeemulator.game.model.player.skills.construction.House;
import net.scapeemulator.game.model.player.skills.construction.HouseStyle;
import net.scapeemulator.game.model.player.skills.construction.hotspot.DoorHotspot;
import net.scapeemulator.game.model.player.skills.construction.hotspot.FurnitureHotspot;
import net.scapeemulator.game.model.player.skills.construction.hotspot.HotspotGroupType;
import net.scapeemulator.game.model.player.skills.construction.hotspot.Hotspot;
import net.scapeemulator.game.model.player.skills.construction.hotspot.HotspotGroup;
import net.scapeemulator.game.model.player.skills.construction.hotspot.FurnitureHotspotType;
import net.scapeemulator.game.model.player.skills.construction.hotspot.WindowHotspot;
/**
* Represents a 'set in stone' room inside a house that can no longer be rotated
* or moved, only furniture can change.
*
* @author David Insley
*/
public class RoomPlaced extends Room {
/**
* Array of hotspots, [x][y][objectgroup]
*/
private Hotspot[][][] hotspots;
private Map<HotspotGroupType, HotspotGroup> groupedHotspots;
/**
* Constructs a room with the given type and rotation.
*
* @param house the house this room is in
* @param type the room type
* @param rotation the rotation
*/
public RoomPlaced(House house, RoomPosition roomPos, RoomType type, Rotation rotation) {
super(house, roomPos, type, rotation);
groupedHotspots = new HashMap<>();
}
public void createHotspots() {
hotspots = new Hotspot[ROOM_SIZE][ROOM_SIZE][ObjectGroup.values().length];
for (int x = 0; x < ROOM_SIZE; x++) {
for (int y = 0; y < ROOM_SIZE; y++) {
GroundObject[] objs = roomType.getHotspotObjs(x, y);
for (int i = 0; i < objs.length; i++) {
GroundObject obj = objs[i];
if (obj == null) {
continue;
}
int newX = x;
int newY = y;
int length = obj.getDefinition().getLength();
int width = obj.getDefinition().getWidth();
int newRot = (obj.getRotation() + roomRotation.getId()) % 4;
if (obj.getRotation() % 2 == 0) {
length = obj.getDefinition().getWidth();
width = obj.getDefinition().getLength();
}
switch (roomRotation) {
case CW_180:
newX = ROOM_SIZE - x - length;
newY = ROOM_SIZE - y - width;
break;
case CW_270:
newX = ROOM_SIZE - y - width;
newY = x;
break;
case CW_90:
newX = y;
newY = ROOM_SIZE - x - length;
break;
case NONE:
break;
}
int height = house.getHeightOffset() + roomPos.getHouseHeight();
int absX = roomPos.getBaseX() + newX;
int absY = roomPos.getBaseY() + newY;
/*
* Because the door hotspot ids change for each style unlike
* all others, we have to make sure we got the right hotspot
* id and door type. The map reader only takes the hotspot
* ids from one style. Hoping to change this eventually.
*/
FurnitureHotspotType type = FurnitureHotspotType.forObjectId(obj.getId());
if (type == FurnitureHotspotType.DOOR) {
DoorType doorType = obj.getId() == DoorType.BASIC_WOOD_1.getHotspotId() ? house.getStyle().getDoorType1() : house.getStyle().getDoorType2();
RoomPlaced adjacent = house.forCoords(height, absX - 1, absY - 1);
if (adjacent == null || adjacent == this) {
adjacent = house.forCoords(height, absX + 1, absY + 1);
}
GroundObject placed = house.getObjectList().put(new Position(absX, absY, height), doorType.getHotspotId(), newRot, obj.getType());
hotspots[newX][newY][i] = new DoorHotspot(this, doorType, roomType.isSolid(), adjacent == this ? null : adjacent, placed);
} else {
GroundObject placed = house.getObjectList().put(new Position(absX, absY, height), obj.getId(), newRot, obj.getType());
if (type == FurnitureHotspotType.WINDOW) {
hotspots[newX][newY][i] = new WindowHotspot(this, placed);
} else {
FurnitureHotspot hotspot = new FurnitureHotspot(this, type, placed);
HotspotGroupType groupType = HotspotGroupType.forType(type);
if (groupType == HotspotGroupType.UNGROUPED) {
hotspots[newX][newY][i] = hotspot;
} else {
HotspotGroup group = groupedHotspots.get(groupType);
if (group == null) {
group = new HotspotGroup(this, groupType);
groupedHotspots.put(groupType, group);
}
group.addHotspot(hotspot);
hotspots[newX][newY][i] = group;
}
}
}
}
}
}
}
/**
* Sets all hotspots in this room to the given mode.
*
* @param building true if the hotspots should be in building mode
*/
public void buildingMode(boolean building) {
for (int x = 0; x < ROOM_SIZE; x++) {
for (int y = 0; y < ROOM_SIZE; y++) {
for (int group = 0; group < ObjectGroup.values().length; group++) {
Hotspot hotspot = hotspots[x][y][group];
if (hotspot != null) {
hotspot.buildingMode(building);
}
}
}
}
}
/**
* Searches for a FurnitureHotspot given the type.
*
* @param type the furniture hotspot type to search for
* @return the hotspot if found, null if not found
*/
public FurnitureHotspot getFurnitureHotspot(FurnitureHotspotType type) {
for (int x = 0; x < ROOM_SIZE; x++) {
for (int y = 0; y < ROOM_SIZE; y++) {
for (Hotspot hotspot : hotspots[x][y]) {
if (hotspot != null && hotspot instanceof FurnitureHotspot) {
FurnitureHotspot fSpot = (FurnitureHotspot) hotspot;
if (fSpot.getType() == type) {
return fSpot;
}
}
}
}
}
return null;
}
/**
* Checks to see if a hotspot exists in this room at the given location. If
* it does, it returns it.
*
* @param x the local x to check
* @param y the local y to check
* @param object the object to find
* @return the hotspot if found, null if not found
*/
public Hotspot getHotspot(int x, int y, GroundObject object) {
for (Hotspot hotspot : hotspots[x][y]) {
if (hotspot != null && hotspot.matchesObject(object)) {
return hotspot;
}
}
return null;
}
/**
* Uses the {@link HouseStyle} of the parent {@link House}, room type, and
* rotation, to create a region tile from the world Construction palette.
*
* @return the generated tile ready to add to a {@link RegionPalette}
*/
public Tile getPaletteSourceTile() {
return new Tile(house.getStyle().getRoomPosition(roomType), roomRotation);
}
public void read(ByteArrayInputStream in) {
if(hotspots == null) {
throw new IllegalStateException("cannot parse furniture data before loading room");
}
for (int pos = in.read(); pos != -1; pos = in.read()) {
int val2 = in.read();
hotspots[pos >> 4][pos & 0xF][val2 & 0xF].setValue(val2 >> 4);
}
}
public void serialize(ByteArrayOutputStream out) {
out.write(roomType.getId());
out.write((roomPos.getHouseX() << 4) | roomPos.getHouseY());
out.write((roomPos.getHouseHeight() << 4) | roomRotation.getId());
for (int x = 0; x < ROOM_SIZE; x++) {
for (int y = 0; y < ROOM_SIZE; y++) {
for (int grp = 0; grp < ObjectGroup.values().length; grp++) {
Hotspot spot = hotspots[x][y][grp];
if (spot != null) {
out.write((x << 4) | y);
out.write((spot.value() << 4) | grp);
}
}
}
}
out.write(-1);
}
}