Raids scouting plugin

This commit is contained in:
Kamiel
2018-02-19 04:20:47 +01:00
committed by Adam
parent 4861b1970a
commit 55a5eaa43d
17 changed files with 1594 additions and 1 deletions

View File

@@ -124,6 +124,8 @@ public interface Client extends GameEngine
int[] getMapRegions();
int[][][] getInstanceTemplateChunks();
int[][] getXteaKeys();
int[] getSettings();

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
public enum InstanceTemplates
{
RAIDS_LOBBY(3264, 5184, 0, 96, 32),
RAIDS_START(3264, 5696, 0, 96, 32),
RAIDS_END(3264, 5152, 0, 64, 32),
RAIDS_SCAVENGERS(3264, 5216, 0, 96, 32),
RAIDS_SHAMANS(3264, 5248, 0, 96, 32),
RAIDS_VASA(3264, 5280, 0, 96, 32),
RAIDS_VANGUARDS(3264, 5312, 0, 96, 32),
RAIDS_ICE_DEMON(3264, 5344, 0, 96, 32),
RAIDS_THIEVING(3264, 5376, 0, 96, 32),
RAIDS_FARMING(3264, 5440, 0, 96, 32),
RAIDS_SCAVENGERS2(3264, 5216, 1, 96, 32),
RAIDS_MUTTADILES(3264, 5312, 1, 96, 32),
RAIDS_MYSTICS(3264, 5248, 1, 96, 32),
RAIDS_TEKTON(3264, 5280, 1, 96, 32),
RAIDS_TIGHTROPE(3264, 5344, 1, 96, 32),
RAIDS_FARMING2(3264, 5440, 1, 96, 32),
RAIDS_GUARDIANS(3264, 5248, 2, 96, 32),
RAIDS_VESPULA(3264, 5280, 2, 96, 32),
RAIDS_CRABS(3264, 5344, 2, 96, 32);
@Getter
private final int baseX;
@Getter
private final int baseY;
@Getter
private final int plane;
@Getter
private final int width;
@Getter
private final int height;
public static InstanceTemplates findMatch(int chunkData)
{
int rotation = chunkData >> 1 & 0x3; //unused, but shows us the rotation of the chunk
int y = (chunkData >> 3 & 0x7FF) * 8;
int x = (chunkData >> 14 & 0x3FF) * 8;
int plane = chunkData >> 24 & 0x3;
for (InstanceTemplates template : InstanceTemplates.values())
{
if (plane == template.getPlane()
&& x >= template.getBaseX() && x < template.getBaseX() + template.getWidth()
&& y >= template.getBaseY() && y < template.getBaseY() + template.getHeight())
{
return template;
}
}
return null;
}
}

View File

@@ -34,7 +34,9 @@ public enum Setting
ATTACK_STYLE(43),
SPECIAL_ATTACK_PERCENT(300),
SPECIAL_ATTACK_ENABLED(301);
SPECIAL_ATTACK_ENABLED(301),
IN_RAID_PARTY(1427);
private final int id;
}

View File

@@ -61,6 +61,7 @@ public class WidgetID
public static final int QUEST_COMPLETED_GROUP_ID = 277;
public static final int CLUE_SCROLL_REWARD_GROUP_ID = 73;
public static final int BARROWS_REWARD_GROUP_ID = 155;
public static final int RAIDS_GROUP_ID = 513;
public static final int MOTHERLODE_MINE_GROUP_ID = 382;
public static final int EXPERIENCE_DROP_GROUP_ID = 122;
public static final int PUZZLE_BOX_GROUP_ID = 306;
@@ -272,6 +273,11 @@ public class WidgetID
static final int NAME_TEXT = 2;
}
static class Raids
{
static final int POINTS_INFOBOX = 3;
}
static class ExperienceDrop
{
static final int DROP_1 = 15;

View File

@@ -175,6 +175,8 @@ public enum WidgetInfo
NIGHTMARE_ZONE(WidgetID.NIGHTMARE_ZONE_GROUP_ID, 1),
RAIDS_POINTS_INFOBOX(WidgetID.RAIDS_GROUP_ID, WidgetID.Raids.POINTS_INFOBOX),
BLAST_FURNACE_COFFER(WidgetID.BLAST_FURNACE_GROUP_ID, 0);
private final int groupId;

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import net.runelite.client.plugins.raids.solver.Layout;
import net.runelite.client.plugins.raids.solver.Room;
public class Raid
{
@Getter
private final RaidRoom[] rooms = new RaidRoom[16];
@Getter
private Layout layout;
public void updateLayout(Layout layout)
{
if (layout == null)
return;
this.layout = layout;
for (int i = 0; i < rooms.length; i++)
{
if (layout.getRoomAt(i) == null)
continue;
RaidRoom room = rooms[i];
if (room == null)
{
RaidRoom.Type type = RaidRoom.Type.fromCode(layout.getRoomAt(i).getSymbol());
room = new RaidRoom(null, type);
if (type == RaidRoom.Type.COMBAT)
room.setBoss(RaidRoom.Boss.UNKNOWN);
if (type == RaidRoom.Type.PUZZLE)
room.setPuzzle(RaidRoom.Puzzle.UNKNOWN);
setRoom(room, i);
}
}
}
public RaidRoom getRoom(int position)
{
return rooms[position];
}
public void setRoom(RaidRoom room, int position)
{
if (position < rooms.length)
rooms[position] = room;
}
public RaidRoom[] getCombatRooms()
{
List<RaidRoom> combatRooms = new ArrayList<>();
for (Room room : layout.getRooms())
{
if (room == null)
continue;
if (rooms[room.getPosition()].getType() == RaidRoom.Type.COMBAT)
combatRooms.add(rooms[room.getPosition()]);
}
return combatRooms.toArray(new RaidRoom[combatRooms.size()]);
}
public String toCode()
{
StringBuilder builder = new StringBuilder();
for (RaidRoom room : rooms)
{
if (room != null)
builder.append(room.getType().getCode());
else
builder.append(" ");
}
return builder.toString();
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Tile;
public class RaidRoom
{
public static final int ROOM_MAX_SIZE = 32;
@AllArgsConstructor
public enum Type
{
START("Start", "#"),
END("End", "¤"),
SCAVENGERS("Scavengers", "S"),
FARMING("Farming", "F"),
COMBAT("Combat", "C"),
PUZZLE("Puzzle", "P"),
EMPTY("Empty", " ");
@Getter
private final String name;
@Getter
private final String code;
public static Type fromCode(char code)
{
for (Type type : Type.values())
{
if (type.getCode().equalsIgnoreCase(String.valueOf(code)))
return type;
}
return Type.EMPTY;
}
}
@AllArgsConstructor
public enum Boss
{
TEKTON("Tekton"),
MUTTADILES("Muttadiles"),
GUARDIANS("Guardians"),
VESPULA("Vespula"),
SHAMANS("Shamans"),
VASA("Vasa"),
VANGUARDS("Vanguards"),
MYSTICS("Mystics"),
UNKNOWN("Unknown");
@Getter
private final String name;
public static Boss fromString(String name)
{
for (Boss boss : Boss.values())
{
if (boss.getName().equalsIgnoreCase(name))
return boss;
}
return null;
}
}
@AllArgsConstructor
public enum Puzzle
{
CRABS("Crabs"),
ICE_DEMON("Ice Demon"),
TIGHTROPE("Tightrope"),
THIEVING("Thieving"),
UNKNOWN("Unknown");
@Getter
private final String name;
public static Puzzle fromString(String name)
{
for (Puzzle puzzle : Puzzle.values())
{
if (puzzle.getName().equalsIgnoreCase(name))
return puzzle;
}
return null;
}
}
@Getter
private final Tile base;
@Getter
@Setter
private Type type;
@Getter
@Setter
private Boss boss;
@Getter
@Setter
private Puzzle puzzle;
@Getter
@Setter
private RaidRoom previousRoom;
@Getter
@Setter
private RaidRoom nextRoom;
public RaidRoom(Tile base, Type type)
{
this.base = base;
this.type = type;
}
@Override
public String toString()
{
switch (type)
{
case COMBAT:
return "RaidRoom (type: " + type.getName() + ", " + boss.getName() + ")";
case PUZZLE:
return "RaidRoom (type: " + type.getName() + ", " + puzzle.getName() + ")";
default:
return "RaidRoom (type: " + type.getName() + ")";
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(
keyName = "raids",
name = "Raids",
description = "Configuration for the raids plugin"
)
public interface RaidsConfig extends Config
{
@ConfigItem(
keyName = "raidsTimer",
name = "Display elapsed raid time",
description = "Display elapsed raid time"
)
default boolean raidsTimer()
{
return true;
}
@ConfigItem(
keyName = "pointsMessage",
name = "Display points in chatbox after raid",
description = "Display a message with total points, individual points and percentage at the end of a raid"
)
default boolean pointsMessage()
{
return true;
}
@ConfigItem(
keyName = "scoutOverlay",
name = "Show scout overlay",
description = "Display an overlay that shows the current raid layout (when entering lobby)"
)
default boolean scoutOverlay()
{
return true;
}
@ConfigItem(
keyName = "scoutOverlayAtBank",
name = "Show scout overlay outside lobby",
description = "Keep the overlay active while at the raids area"
)
default boolean scoutOverlayAtBank()
{
return true;
}
@ConfigItem(
keyName = "blacklistedRooms",
name = "Blacklisted rooms",
description = "Display blacklisted rooms in red on the overlay. Separate with comma (full name)"
)
default String blacklistedRooms()
{
return "";
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import javax.inject.Inject;
import lombok.Setter;
import net.runelite.client.plugins.raids.solver.Room;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.components.PanelComponent;
public class RaidsOverlay extends Overlay
{
private RaidsPlugin plugin;
private RaidsConfig config;
private final PanelComponent panelComponent = new PanelComponent();
@Setter
private boolean scoutOverlayShown = false;
@Inject
public RaidsOverlay(RaidsPlugin plugin, RaidsConfig config)
{
setPosition(OverlayPosition.TOP_LEFT);
setPriority(OverlayPriority.LOW);
this.plugin = plugin;
this.config = config;
}
@Override
public Dimension render(Graphics2D graphics, Point parent)
{
if (!config.scoutOverlay() || !scoutOverlayShown)
{
return null;
}
panelComponent.getLines().clear();
if (plugin.getRaid() == null || plugin.getRaid().getLayout() == null)
{
panelComponent.setTitleColor(Color.RED);
panelComponent.setTitle("Unable to scout this raid!");
return panelComponent.render(graphics, parent);
}
panelComponent.setTitleColor(Color.WHITE);
panelComponent.setTitle("Raid scouter");
for (Room layoutRoom : plugin.getRaid().getLayout().getRooms())
{
int position = layoutRoom.getPosition();
RaidRoom room = plugin.getRaid().getRoom(position);
if (room == null)
{
continue;
}
Color color = Color.WHITE;
switch (room.getType())
{
case COMBAT:
if (plugin.getBlacklist().contains(room.getBoss().getName().toLowerCase()))
{
color = Color.RED;
}
panelComponent.getLines().add(new PanelComponent.Line(
room.getType().getName(), Color.WHITE, room.getBoss().getName(), color
));
break;
case PUZZLE:
if (plugin.getBlacklist().contains(room.getPuzzle().getName().toLowerCase()))
{
color = Color.RED;
}
panelComponent.getLines().add(new PanelComponent.Line(
room.getType().getName(), Color.WHITE, room.getPuzzle().getName(), color
));
break;
}
}
return panelComponent.render(graphics, parent);
}
}

View File

@@ -0,0 +1,472 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Binder;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import static net.runelite.api.Perspective.SCENE_SIZE;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.chat.ChatColor;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.raids.solver.Layout;
import net.runelite.client.plugins.raids.solver.LayoutSolver;
import net.runelite.client.plugins.raids.solver.RotationSolver;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor(
name = "Raids Plugin"
)
@Slf4j
public class RaidsPlugin extends Plugin
{
private static final int LOBBY_PLANE = 3;
private static final String RAID_START_MESSAGE = "The raid has begun!";
private static final String RAID_COMPLETE_MESSAGE = "Congratulations - your raid is complete!";
private static final int TOTAL_POINTS = 0, PERSONAL_POINTS = 1, TEXT_CHILD = 4;
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##");
private BufferedImage raidsIcon;
private RaidsTimer timer;
private boolean inRaidChambers;
@Inject
private ChatMessageManager chatMessageManager;
@Inject
private InfoBoxManager infoBoxManager;
@Inject
private Client client;
@Inject
private RaidsConfig config;
@Inject
private RaidsOverlay overlay;
@Inject
private LayoutSolver layoutSolver;
@Getter
private Raid raid;
@Getter
private ArrayList<String> blacklist = new ArrayList<>();
@Provides
RaidsConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(RaidsConfig.class);
}
@Override
public void configure(Binder binder)
{
binder.bind(RaidsOverlay.class);
}
@Override
public Overlay getOverlay()
{
return overlay;
}
@Override
protected void startUp() throws Exception
{
if (client.getGameState() == GameState.LOGGED_IN)
{
inRaidChambers = client.getSetting(Varbits.IN_RAID) == 1;
updateInfoBoxState();
}
updateBlacklist();
}
@Override
protected void shutDown() throws Exception
{
if (timer != null)
infoBoxManager.removeInfoBox(timer);
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (config.pointsMessage())
cacheColors();
if (event.getKey().equals("raidsTimer"))
updateInfoBoxState();
if (event.getKey().equals("blacklistedRooms"))
updateBlacklist();
}
@Subscribe
public void onVarbitChange(VarbitChanged event)
{
boolean setting = client.getSetting(Varbits.IN_RAID) == 1;
if (inRaidChambers != setting)
{
inRaidChambers = setting;
updateInfoBoxState();
if (inRaidChambers)
{
raid = buildRaid();
if (raid == null)
{
log.debug("Failed to build raid");
return;
}
Layout layout = layoutSolver.findLayout(raid.toCode());
if (layout == null)
{
log.debug("Could not find layout match");
return;
}
raid.updateLayout(layout);
RotationSolver.solve(raid.getCombatRooms());
overlay.setScoutOverlayShown(true);
}
else if (!config.scoutOverlayAtBank())
{
overlay.setScoutOverlayShown(false);
raid = null;
}
}
if (client.getSetting(Setting.IN_RAID_PARTY) == -1)
{
overlay.setScoutOverlayShown(false);
raid = null;
}
}
@Subscribe
public void onChatMessage(ChatMessage event)
{
if (inRaidChambers && event.getType() == ChatMessageType.CLANCHAT_INFO)
{
String message = event.getMessage().replaceAll("<[^>]*>", "");
if (config.raidsTimer() && message.startsWith(RAID_START_MESSAGE))
{
timer = new RaidsTimer(getRaidsIcon(), Instant.now());
infoBoxManager.addInfoBox(timer);
}
if (message.startsWith(RAID_COMPLETE_MESSAGE))
{
if (timer != null)
timer.setStopped(true);
if (config.pointsMessage())
{
Widget raidsWidget = client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX).getChild(TEXT_CHILD);
String[] raidPoints = raidsWidget.getText().split("<br>");
int totalPoints = Integer.parseInt(raidPoints[TOTAL_POINTS].replace(",", ""));
int personalPoints = Integer.parseInt(raidPoints[PERSONAL_POINTS].replace(",", ""));
double percentage = personalPoints / (totalPoints / 100.0);
String chatMessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Total points: ")
.append(ChatColorType.HIGHLIGHT)
.append(raidPoints[TOTAL_POINTS])
.append(ChatColorType.NORMAL)
.append(", Personal points: ")
.append(ChatColorType.HIGHLIGHT)
.append(raidPoints[PERSONAL_POINTS])
.append(ChatColorType.NORMAL)
.append(" (")
.append(ChatColorType.HIGHLIGHT)
.append(DECIMAL_FORMAT.format(percentage))
.append(ChatColorType.NORMAL)
.append("%)")
.build();
chatMessageManager.queue(ChatMessageType.CLANCHAT_INFO, chatMessage);
}
}
}
}
private void updateInfoBoxState()
{
if (timer != null)
{
if (inRaidChambers && config.raidsTimer())
infoBoxManager.addInfoBox(timer);
else
infoBoxManager.removeInfoBox(timer);
if (!inRaidChambers)
timer = null;
}
}
private void updateBlacklist()
{
blacklist.clear();
blacklist.addAll(Arrays.asList(config.blacklistedRooms().toLowerCase().split(", ")));
}
private void cacheColors()
{
chatMessageManager.cacheColor(new ChatColor(ChatColorType.NORMAL, Color.BLACK, false), ChatMessageType.CLANCHAT_INFO)
.cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, Color.RED, false), ChatMessageType.CLANCHAT_INFO)
.cacheColor(new ChatColor(ChatColorType.NORMAL, Color.WHITE, true), ChatMessageType.CLANCHAT_INFO)
.cacheColor(new ChatColor(ChatColorType.HIGHLIGHT, Color.RED, true), ChatMessageType.CLANCHAT_INFO)
.refreshAll();
}
private Point findLobbyBase()
{
Tile[][] tiles = client.getRegion().getTiles()[LOBBY_PLANE];
for (int x = 0; x < SCENE_SIZE; x++)
{
for (int y = 0; y < SCENE_SIZE; y++)
{
if (tiles[x][y] == null || tiles[x][y].getWallObject() == null)
continue;
if (tiles[x][y].getWallObject().getId() == ObjectID.NULL_12231)
return tiles[x][y].getRegionLocation();
}
}
return null;
}
private Raid buildRaid()
{
Point gridBase = findLobbyBase();
if (gridBase == null)
return null;
Raid raid = new Raid();
Tile[][] tiles;
int position, x, y, offsetX;
int startX = -2;
for (int plane = 3; plane > 1; plane--)
{
tiles = client.getRegion().getTiles()[plane];
if (tiles[gridBase.getX() + RaidRoom.ROOM_MAX_SIZE][gridBase.getY()] == null)
position = 1;
else
position = 0;
for (int i = 1; i > -2; i--)
{
y = gridBase.getY() + (i * RaidRoom.ROOM_MAX_SIZE);
for (int j = startX; j < 4; j++)
{
x = gridBase.getX() + (j * RaidRoom.ROOM_MAX_SIZE);
offsetX = 0;
if (x > SCENE_SIZE && position > 1 && position < 4)
position++;
if (x < 0)
offsetX = Math.abs(x) + 1; //add 1 because the tile at x=0 will always be null
if (x < SCENE_SIZE && y >= 0 && y < SCENE_SIZE)
{
if (tiles[x + offsetX][y] == null)
{
if (position == 4)
{
position++;
break;
}
continue;
}
if (position == 0 && startX != j)
startX = j;
Tile base = tiles[offsetX > 0 ? 1 : x][y];
RaidRoom room = determineRoom(base);
raid.setRoom(room, position + Math.abs((plane - 3) * 8));
position++;
}
}
}
}
return raid;
}
private RaidRoom determineRoom(Tile base)
{
RaidRoom room = new RaidRoom(base, RaidRoom.Type.EMPTY);
int chunkData = client.getInstanceTemplateChunks()[base.getPlane()][(base.getRegionLocation().getX()) / 8][base.getRegionLocation().getY() / 8];
InstanceTemplates template = InstanceTemplates.findMatch(chunkData);
if (template == null)
return room;
switch (template)
{
case RAIDS_LOBBY:
case RAIDS_START:
room.setType(RaidRoom.Type.START);
break;
case RAIDS_END:
room.setType(RaidRoom.Type.END);
break;
case RAIDS_SCAVENGERS:
case RAIDS_SCAVENGERS2:
room.setType(RaidRoom.Type.SCAVENGERS);
break;
case RAIDS_SHAMANS:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.SHAMANS);
break;
case RAIDS_VASA:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.VASA);
break;
case RAIDS_VANGUARDS:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.VANGUARDS);
break;
case RAIDS_ICE_DEMON:
room.setType(RaidRoom.Type.PUZZLE);
room.setPuzzle(RaidRoom.Puzzle.ICE_DEMON);
break;
case RAIDS_THIEVING:
room.setType(RaidRoom.Type.PUZZLE);
room.setPuzzle(RaidRoom.Puzzle.THIEVING);
break;
case RAIDS_FARMING:
case RAIDS_FARMING2:
room.setType(RaidRoom.Type.FARMING);
break;
case RAIDS_MUTTADILES:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.MUTTADILES);
break;
case RAIDS_MYSTICS:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.MYSTICS);
break;
case RAIDS_TEKTON:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.TEKTON);
break;
case RAIDS_TIGHTROPE:
room.setType(RaidRoom.Type.PUZZLE);
room.setPuzzle(RaidRoom.Puzzle.TIGHTROPE);
break;
case RAIDS_GUARDIANS:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.GUARDIANS);
break;
case RAIDS_CRABS:
room.setType(RaidRoom.Type.PUZZLE);
room.setPuzzle(RaidRoom.Puzzle.CRABS);
break;
case RAIDS_VESPULA:
room.setType(RaidRoom.Type.COMBAT);
room.setBoss(RaidRoom.Boss.VESPULA);
break;
}
return room;
}
private BufferedImage getRaidsIcon()
{
if (raidsIcon != null)
return raidsIcon;
InputStream in = RaidsPlugin.class.getResourceAsStream("raids_icon.png");
try
{
raidsIcon = ImageIO.read(in);
}
catch (IOException ex)
{
log.warn("Unable to load image", ex);
}
return raidsIcon;
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import lombok.Setter;
import net.runelite.client.ui.overlay.infobox.InfoBox;
public class RaidsTimer extends InfoBox
{
private final Instant startTime;
private LocalTime time;
@Setter
private boolean stopped;
public RaidsTimer(BufferedImage image, Instant startTime)
{
super(image);
this.startTime = startTime;
stopped = false;
}
@Override
public String getText()
{
if (startTime == null)
return "";
if (!stopped)
{
Duration elapsed = Duration.between(startTime, Instant.now());
time = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
if (time.getHour() > 0)
return time.format(DateTimeFormatter.ofPattern("HH:mm"));
return time.format(DateTimeFormatter.ofPattern("mm:ss"));
}
@Override
public Color getTextColor()
{
if (stopped)
return Color.GREEN;
return Color.WHITE;
}
@Override
public String getTooltip()
{
return "Elapsed raid time: " + time.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids.solver;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
public class Layout
{
@Getter
private final List<Room> rooms = new ArrayList<>();
public void add(Room room)
{
rooms.add(room);
}
public Room getRoomAt(int position)
{
for (Room room : rooms)
{
if (room.getPosition() == position)
return room;
}
return null;
}
public String toCode()
{
StringBuilder builder = new StringBuilder();
for (Room room : rooms)
{
builder.append(room.getSymbol());
}
return builder.toString();
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids.solver;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/*
* Implementation of https://github.com/WooxSolo/raids-layout
* Copyright (c) 2017 WooxSolo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
@Slf4j
@Singleton
public class LayoutSolver
{
@Getter
private static final List<Layout> layouts = new ArrayList<>();
private static final Pattern regex = Pattern.compile("^([A-Z]*)\\.([A-Z]*) - #([A-Z]*)#([A-Z]*)$");
private static final String[] codes =
{
"CFSCP.PCSCF - #ENWWWS#NEESEN",
"CFSCPC.PCSCPF - #WSEENES#WWWNEEE",
"CSFCP.CSCPF - #ENESEN#WWWSEE",
"CSPFC.CCSSF - #NEESEN#WSWWNE",
"FCPCC.PSCSF - #WWWSEE#ENWWSW",
"FSCCP.PCSCF - #WNWSWN#ESEENW",
"FSCCS.PCPSF - #WSEEEN#WSWNWS",
"FSCPC.CSCPF - #WNWWSE#EENWWW",
"PCSFC.PCSCF - #WNEEES#NWSWNW",
"SCCFC.PSCSF - #EEENWW#WSEEEN",
"SCCFP.CCSPF - #NESEEN#WSWNWS",
"SCFCP.CCSPF - #ESEENW#ESWWNW",
"SCFCP.CSCFS - #ENEESW#ENWWSW",
"SCFCPC.CSPCSF - #ESWWNWS#NESENES",
"SCFPC.CSPCF - #WSWWNE#WSEENE",
"SCFPC.PCCSF - #WSEENE#WWWSEE",
"SCFPC.SCPCF - #NESENE#WSWWNE",
"SCPFC.CCPSF - #NWWWSE#WNEESE",
"SCPFC.CSPCF - #NEEESW#WWNEEE",
"SCPFC.CSPSF - #WWSEEE#NWSWWN",
"SCSPF.CCSPF - #ESWWNW#ESENES",
"SFCCP.CSCPF - #WNEESE#NWSWWN",
"SFCCS.PCPSF - #ENWWSW#ENESEN",
"SPCFC.CSPCF - #WWNEEE#WSWNWS",
"SPCFC.SCCPF - #ESENES#WWWNEE",
"SPSFP.CCCSF - #NWSWWN#ESEENW",
};
public LayoutSolver()
{
build();
}
public Layout findLayout(String code)
{
Layout solution = null;
int matches = 0;
boolean match;
for (Layout layout : layouts)
{
match = true;
for (int i = 0; i < code.length(); i++)
{
Room room = layout.getRoomAt(i);
char c = code.charAt(i);
if (room != null && c != ' ' && c != room.getSymbol())
{
match = false;
break;
}
}
if (match)
{
solution = layout;
matches++;
log.debug("Found matching layout: " + layout.toCode());
}
}
if (matches == 1)
return solution;
else
return null;
}
private int calcStart(String directions)
{
int startPos = 0;
int position = 0;
for (int i = 0; i < directions.length(); i++)
{
char c = directions.charAt(i);
int delta = dirToPosDelta(c);
position += delta;
if (position < 0 || position >= 8 || (position == 3 && delta == -1) || (position == 4 && delta == 1))
{
position -= delta;
startPos -= delta;
}
}
return startPos;
}
private int dirToPosDelta(char direction)
{
switch (String.valueOf(direction))
{
case "N":
return -4;
case "E":
return 1;
case "S":
return 4;
case "W":
return -1;
default:
return 0;
}
}
private void build()
{
for (String code : codes)
{
Matcher match = regex.matcher(code);
if (!match.find())
continue;
String symbols, directions;
int position = calcStart(match.group(3));
Layout layout = new Layout();
Room lastRoom = null;
Room room;
for (int floor = 0; floor < 2; floor++)
{
symbols = match.group(1 + floor);
directions = match.group(3 + floor);
for (int i = 0; i < directions.length(); i++)
{
char symbol = (i == 0 ? '#' : symbols.charAt(i - 1));
room = new Room(position, symbol);
if (lastRoom != null)
{
lastRoom.setNext(room);
room.setPrevious(lastRoom);
}
layout.add(room);
lastRoom = room;
int delta = dirToPosDelta(directions.charAt(i));
position += delta;
}
room = new Room(position, '¤');
room.setPrevious(lastRoom);
lastRoom.setNext(room);
layout.add(room);
position += 8;
}
layouts.add(layout);
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids.solver;
import lombok.Getter;
import lombok.Setter;
public class Room
{
@Getter
private final int position;
@Getter
private final char symbol;
@Getter
@Setter
private Room next;
@Getter
@Setter
private Room previous;
Room(int position, char symbol)
{
this.position = position;
this.symbol = symbol;
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2018, Kamiel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.raids.solver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import net.runelite.client.plugins.raids.RaidRoom;
import net.runelite.client.plugins.raids.RaidRoom.Boss;
public class RotationSolver
{
private static class Rotation<E> extends ArrayList<E>
{
Rotation(Collection<? extends E> bosses)
{
super(bosses);
}
@Override
public E get(int index)
{
if (index < 0)
index = index + size();
return super.get(index % size());
}
}
private static final Rotation[] ROTATIONS =
{
new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.VASA, Boss.GUARDIANS, Boss.MYSTICS, Boss.SHAMANS, Boss.MUTTADILES, Boss.VANGUARDS, Boss.VESPULA)),
new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.MUTTADILES, Boss.GUARDIANS, Boss.VESPULA, Boss.SHAMANS, Boss.VASA, Boss.VANGUARDS, Boss.MYSTICS)),
new Rotation<>(Arrays.asList(Boss.VESPULA, Boss.VANGUARDS, Boss.MUTTADILES, Boss.SHAMANS, Boss.MYSTICS, Boss.GUARDIANS, Boss.VASA, Boss.TEKTON)),
new Rotation<>(Arrays.asList(Boss.MYSTICS, Boss.VANGUARDS, Boss.VASA, Boss.SHAMANS, Boss.VESPULA, Boss.GUARDIANS, Boss.MUTTADILES, Boss.TEKTON))
};
public static boolean solve(RaidRoom[] rooms)
{
if (rooms == null)
return false;
Rotation<Boss> match = null;
Integer start = null;
Integer index = null;
int known = 0;
for (int i = 0; i < rooms.length; i++)
{
if (rooms[i] == null || rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN)
continue;
if (start == null)
start = i;
known++;
}
if (known < 2)
return false;
if (known == rooms.length)
return true;
for (Rotation rotation : ROTATIONS)
{
COMPARE:
for (int i = 0; i < rotation.size(); i++)
{
if (rooms[start].getBoss() == rotation.get(i))
{
for (int j = start + 1; j < rooms.length; j++)
{
if (rooms[j].getBoss() == null || rooms[j].getBoss() == Boss.UNKNOWN)
continue;
if (rooms[j].getBoss() != rotation.get(i + j - start))
break COMPARE;
}
if (match != null && match != rotation)
return false;
index = i - start;
match = rotation;
}
}
}
if (match == null)
return false;
for (int i = 0; i < rooms.length; i++)
{
if (rooms[i] == null)
continue;
if (rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN)
rooms[i].setBoss(match.get(index + i));
}
return true;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -276,6 +276,10 @@ public interface RSClient extends RSGameEngine, Client
@Override
int[] getMapRegions();
@Import("instanceTemplateChunks")
@Override
int[][][] getInstanceTemplateChunks();
@Import("xteaKeys")
@Override
int[][] getXteaKeys();