Merge branch 'master' into maven

This commit is contained in:
Tyler Bochard
2019-07-11 00:48:18 -04:00
committed by GitHub
96 changed files with 6320 additions and 3754 deletions

View File

@@ -22,34 +22,41 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.cache.definitions.sound; package net.runelite.cache.definitions.loaders.sound;
public class SoundEffect1Definition import net.runelite.cache.definitions.sound.AudioEnvelopeDefinition;
import net.runelite.cache.io.InputStream;
public class AudioEnvelopeLoader
{ {
public SoundEffect2Definition field1173; public AudioEnvelopeDefinition load(InputStream in)
public SoundEffect2Definition field1174;
public SoundEffect2Definition field1175;
public int field1176 = 500;
public int[] field1177 = new int[]
{ {
0, 0, 0, 0, 0 AudioEnvelopeDefinition audioEnvelope = new AudioEnvelopeDefinition();
};
public SoundEffect2Definition field1178; load(audioEnvelope, in);
public int[] field1179 = new int[]
return audioEnvelope;
}
private void load(AudioEnvelopeDefinition audioEnvelope, InputStream in)
{ {
0, 0, 0, 0, 0 audioEnvelope.form = in.readUnsignedByte();
}; audioEnvelope.start = in.readInt();
public int[] field1180 = new int[] audioEnvelope.end = in.readInt();
this.loadSegments(audioEnvelope, in);
}
final void loadSegments(AudioEnvelopeDefinition audioEnvelope, InputStream in)
{ {
0, 0, 0, 0, 0 audioEnvelope.segments = in.readUnsignedByte();
}; audioEnvelope.durations = new int[audioEnvelope.segments];
public SoundEffect2Definition field1181; audioEnvelope.phases = new int[audioEnvelope.segments];
public SoundEffect3Definition field1182;
public SoundEffect2Definition field1183; for (int i = 0; i < audioEnvelope.segments; ++i)
public int field1184 = 100; {
public SoundEffect2Definition field1186; audioEnvelope.durations[i] = in.readUnsignedShort();
public int field1187 = 0; audioEnvelope.phases[i] = in.readUnsignedShort();
public int field1188 = 0; }
public SoundEffect2Definition field1192;
public SoundEffect2Definition field1193; }
} }

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.loaders.sound;
import net.runelite.cache.definitions.sound.InstrumentDefinition;
import net.runelite.cache.definitions.sound.AudioEnvelopeDefinition;
import net.runelite.cache.io.InputStream;
public class InstrumentLoader
{
private final AudioEnvelopeLoader aeLoader = new AudioEnvelopeLoader();
private final SoundEffectLoader seLoader = new SoundEffectLoader();
public InstrumentDefinition load(InputStream in)
{
InstrumentDefinition instrument = new InstrumentDefinition();
load(instrument, in);
return instrument;
}
private void load(InstrumentDefinition instrument, InputStream in)
{
instrument.pitch = aeLoader.load(in);
instrument.volume = aeLoader.load(in);
int volume = in.readUnsignedByte();
if (volume != 0)
{
in.setOffset(in.getOffset() - 1);
instrument.pitchModifier = aeLoader.load(in);
instrument.pitchModifierAmplitude = aeLoader.load(in);
}
volume = in.readUnsignedByte();
if (volume != 0)
{
in.setOffset(in.getOffset() - 1);
instrument.volumeMultiplier = aeLoader.load(in);
instrument.volumeMultiplierAmplitude = aeLoader.load(in);
}
volume = in.readUnsignedByte();
if (volume != 0)
{
in.setOffset(in.getOffset() - 1);
instrument.release = aeLoader.load(in);
instrument.field1175 = aeLoader.load(in);
}
for (int i = 0; i < 10; ++i)
{
int vol = in.readUnsignedShortSmart();
if (vol == 0)
{
break;
}
instrument.oscillatorVolume[i] = vol;
instrument.oscillatorPitch[i] = in.readShortSmart();
instrument.oscillatorDelays[i] = in.readUnsignedShortSmart();
}
instrument.delayTime = in.readUnsignedShortSmart();
instrument.delayDecay = in.readUnsignedShortSmart();
instrument.duration = in.readUnsignedShort();
instrument.offset = in.readUnsignedShort();
instrument.filterEnvelope = new AudioEnvelopeDefinition();
instrument.filter = seLoader.load(in, instrument.filterEnvelope);
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.loaders.sound;
import net.runelite.cache.definitions.sound.SoundEffect1Definition;
import net.runelite.cache.definitions.sound.SoundEffect2Definition;
import net.runelite.cache.io.InputStream;
public class SoundEffect1Loader
{
private final SoundEffect2Loader se2Loader = new SoundEffect2Loader();
private final SoundEffect3Loader se3Loader = new SoundEffect3Loader();
public SoundEffect1Definition load(InputStream in)
{
SoundEffect1Definition se = new SoundEffect1Definition();
load(se, in);
return se;
}
private void load(SoundEffect1Definition se, InputStream var1)
{
se.field1181 = se2Loader.load(var1);
se.field1173 = se2Loader.load(var1);
int var2 = var1.readUnsignedByte();
if (var2 != 0)
{
var1.setOffset(var1.getOffset() - 1);
se.field1174 = se2Loader.load(var1);
se.field1193 = se2Loader.load(var1);
}
var2 = var1.readUnsignedByte();
if (var2 != 0)
{
var1.setOffset(var1.getOffset() - 1);
se.field1183 = se2Loader.load(var1);
se.field1192 = se2Loader.load(var1);
}
var2 = var1.readUnsignedByte();
if (var2 != 0)
{
var1.setOffset(var1.getOffset() - 1);
se.field1178 = se2Loader.load(var1);
se.field1175 = se2Loader.load(var1);
}
for (int var3 = 0; var3 < 10; ++var3)
{
int var4 = var1.readUnsignedShortSmart();
if (var4 == 0)
{
break;
}
se.field1180[var3] = var4;
se.field1179[var3] = var1.readShortSmart();
se.field1177[var3] = var1.readUnsignedShortSmart();
}
se.field1187 = var1.readUnsignedShortSmart();
se.field1184 = var1.readUnsignedShortSmart();
se.field1176 = var1.readUnsignedShort();
se.field1188 = var1.readUnsignedShort();
se.field1186 = new SoundEffect2Definition();
se.field1182 = se3Loader.load(var1, se.field1186);
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.loaders.sound;
import net.runelite.cache.definitions.sound.SoundEffect2Definition;
import net.runelite.cache.definitions.sound.SoundEffect3Definition;
import net.runelite.cache.io.InputStream;
public class SoundEffect3Loader
{
private final SoundEffect2Loader se2Loader = new SoundEffect2Loader();
public SoundEffect3Definition load(InputStream in, SoundEffect2Definition var2)
{
SoundEffect3Definition se = new SoundEffect3Definition();
load(se, in, var2);
return se;
}
private void load(SoundEffect3Definition se, InputStream var1, SoundEffect2Definition var2)
{
int var3 = var1.readUnsignedByte();
se.field1155[0] = var3 >> 4;
se.field1155[1] = var3 & 15;
if (var3 != 0)
{
se.field1156[0] = var1.readUnsignedShort();
se.field1156[1] = var1.readUnsignedShort();
int var4 = var1.readUnsignedByte();
int var5;
int var6;
for (var5 = 0; var5 < 2; ++var5)
{
for (var6 = 0; var6 < se.field1155[var5]; ++var6)
{
se.field1154[var5][0][var6] = var1.readUnsignedShort();
se.field1159[var5][0][var6] = var1.readUnsignedShort();
}
}
for (var5 = 0; var5 < 2; ++var5)
{
for (var6 = 0; var6 < se.field1155[var5]; ++var6)
{
if ((var4 & 1 << var5 * 4 << var6) != 0)
{
se.field1154[var5][1][var6] = var1.readUnsignedShort();
se.field1159[var5][1][var6] = var1.readUnsignedShort();
}
else
{
se.field1154[var5][1][var6] = se.field1154[var5][0][var6];
se.field1159[var5][1][var6] = se.field1159[var5][0][var6];
}
}
}
if (var4 != 0 || se.field1156[1] != se.field1156[0])
{
se2Loader.method1144(var2, var1);
}
}
else
{
int[] var7 = se.field1156;
se.field1156[1] = 0;
var7[0] = 0;
}
}
}

View File

@@ -24,39 +24,70 @@
*/ */
package net.runelite.cache.definitions.loaders.sound; package net.runelite.cache.definitions.loaders.sound;
import net.runelite.cache.definitions.sound.AudioEnvelopeDefinition;
import net.runelite.cache.definitions.sound.SoundEffectDefinition; import net.runelite.cache.definitions.sound.SoundEffectDefinition;
import net.runelite.cache.definitions.sound.SoundEffect1Definition;
import net.runelite.cache.io.InputStream; import net.runelite.cache.io.InputStream;
public class SoundEffectLoader public class SoundEffectLoader
{ {
public SoundEffectDefinition load(byte[] b) private final AudioEnvelopeLoader audioEnvelopeLoader = new AudioEnvelopeLoader();
public SoundEffectDefinition load(InputStream in, AudioEnvelopeDefinition audioEnvelope)
{ {
SoundEffectDefinition se = new SoundEffectDefinition(); SoundEffectDefinition soundEffect = new SoundEffectDefinition();
InputStream in = new InputStream(b);
load(se, in); load(soundEffect, audioEnvelope, in);
return se; return soundEffect;
} }
private void load(SoundEffectDefinition se, InputStream var1) private void load(SoundEffectDefinition soundEffect, AudioEnvelopeDefinition audioEnvelope, InputStream in)
{ {
for (int var2 = 0; var2 < 10; ++var2) int id = in.readUnsignedByte();
soundEffect.pairs[0] = id >> 4;
soundEffect.pairs[1] = id & 15;
if (id != 0)
{ {
int var3 = var1.readUnsignedByte(); soundEffect.unity[0] = in.readUnsignedShort();
if (var3 != 0) soundEffect.unity[1] = in.readUnsignedShort();
int track = in.readUnsignedByte();
for (int i = 0; i < 2; ++i)
{ {
var1.setOffset(var1.getOffset() - 1); for (int j = 0; j < soundEffect.pairs[i]; ++j)
{
soundEffect.phases[i][0][j] = in.readUnsignedShort();
soundEffect.magnitudes[i][0][j] = in.readUnsignedShort();
}
}
SoundEffect1Loader se1Loader = new SoundEffect1Loader(); for (int i = 0; i < 2; ++i)
SoundEffect1Definition se1 = se1Loader.load(var1); {
for (int j = 0; j < soundEffect.pairs[i]; ++j)
{
if ((track & 1 << i * 4 << j) != 0)
{
soundEffect.phases[i][1][j] = in.readUnsignedShort();
soundEffect.magnitudes[i][1][j] = in.readUnsignedShort();
}
else
{
soundEffect.phases[i][1][j] = soundEffect.phases[i][0][j];
soundEffect.magnitudes[i][1][j] = soundEffect.magnitudes[i][0][j];
}
}
}
se.field1008[var2] = se1; if (track != 0 || soundEffect.unity[1] != soundEffect.unity[0])
{
audioEnvelopeLoader.loadSegments(audioEnvelope, in);
} }
} }
else
se.field1006 = var1.readUnsignedShort(); {
se.field1009 = var1.readUnsignedShort(); int[] clean = soundEffect.unity;
soundEffect.unity[1] = 0;
clean[0] = 0;
}
} }
} }

View File

@@ -24,39 +24,39 @@
*/ */
package net.runelite.cache.definitions.loaders.sound; package net.runelite.cache.definitions.loaders.sound;
import net.runelite.cache.definitions.sound.SoundEffect2Definition; import net.runelite.cache.definitions.sound.SoundEffectTrackDefinition;
import net.runelite.cache.definitions.sound.InstrumentDefinition;
import net.runelite.cache.io.InputStream; import net.runelite.cache.io.InputStream;
public class SoundEffect2Loader public class SoundEffectTrackLoader
{ {
public SoundEffect2Definition load(InputStream in) public SoundEffectTrackDefinition load(byte[] b)
{ {
SoundEffect2Definition se = new SoundEffect2Definition(); SoundEffectTrackDefinition soundEffect = new SoundEffectTrackDefinition();
InputStream in = new InputStream(b);
load(se, in); load(soundEffect, in);
return se; return soundEffect;
} }
private void load(SoundEffect2Definition se, InputStream var1) private void load(SoundEffectTrackDefinition soundEffect, InputStream in)
{ {
se.field1087 = var1.readUnsignedByte(); for (int i = 0; i < 10; ++i)
se.field1088 = var1.readInt();
se.field1089 = var1.readInt();
this.method1144(se, var1);
}
final void method1144(SoundEffect2Definition se, InputStream var1)
{
se.field1092 = var1.readUnsignedByte();
se.field1086 = new int[se.field1092];
se.field1090 = new int[se.field1092];
for (int var2 = 0; var2 < se.field1092; ++var2)
{ {
se.field1086[var2] = var1.readUnsignedShort(); int volume = in.readUnsignedByte();
se.field1090[var2] = var1.readUnsignedShort(); if (volume != 0)
{
in.setOffset(in.getOffset() - 1);
InstrumentLoader instrumentLoader = new InstrumentLoader();
InstrumentDefinition instrument = instrumentLoader.load(in);
soundEffect.instruments[i] = instrument;
}
} }
soundEffect.start = in.readUnsignedShort();
soundEffect.end = in.readUnsignedShort();
} }
} }

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.sound;
public class AudioEnvelopeDefinition
{
public int segments = 2;
public int[] durations = new int[2];
public int[] phases = new int[2];
public int start;
public int end;
public int form;
public int ticks;
public int phaseIndex;
public int step;
public int amplitude;
public int max;
public AudioEnvelopeDefinition()
{
this.durations[0] = 0;
this.durations[1] = '\uffff';
this.phases[0] = 0;
this.phases[1] = '\uffff';
}
public final int step(int var1)
{
if (this.max >= this.ticks)
{
this.amplitude = this.phases[this.phaseIndex++] << 15;
if (this.phaseIndex >= this.segments)
{
this.phaseIndex = this.segments - 1;
}
this.ticks = (int) ((double) this.durations[this.phaseIndex] / 65536.0 * (double) var1);
if (this.ticks > this.max)
{
this.step = ((this.phases[this.phaseIndex] << 15) - this.amplitude) / (this.ticks - this.max);
}
}
this.amplitude += this.step;
++this.max;
return this.amplitude - this.step >> 15;
}
public final void reset()
{
this.ticks = 0;
this.phaseIndex = 0;
this.step = 0;
this.amplitude = 0;
this.max = 0;
}
}

View File

@@ -0,0 +1,356 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.sound;
import java.util.Random;
public class InstrumentDefinition
{
public AudioEnvelopeDefinition volume;
public AudioEnvelopeDefinition pitchModifier;
public AudioEnvelopeDefinition field1175;
public AudioEnvelopeDefinition release;
public AudioEnvelopeDefinition volumeMultiplier;
public AudioEnvelopeDefinition volumeMultiplierAmplitude;
public AudioEnvelopeDefinition pitchModifierAmplitude;
public AudioEnvelopeDefinition pitch;
public int[] oscillatorDelays = new int[]
{
0, 0, 0, 0, 0
};
public int[] oscillatorPitch = new int[]
{
0, 0, 0, 0, 0
};
public int[] oscillatorVolume = new int[]
{
0, 0, 0, 0, 0
};
public SoundEffectDefinition filter;
public AudioEnvelopeDefinition filterEnvelope;
static int[] samples = new int[220500];
static int[] NOISE = new int[32768];
static int[] AUDIO_SINE = new int[32768];
static int[] phases = new int[5];
static int[] delays = new int[5];
static int[] volumeSteps = new int[5];
static int[] pitchSteps = new int[5];
static int[] pitchBaseSteps = new int[5];
public int duration = 500;
public int delayDecay = 100;
public int delayTime = 0;
public int offset = 0;
static
{
Random random = new Random(0);
for (int i = 0; i < 32768; ++i)
{
InstrumentDefinition.NOISE[i] = (random.nextInt() & 2) - 1;
InstrumentDefinition.AUDIO_SINE[i] = (int) (Math.sin((double) i / 5215.1903) * 16384.0);
}
}
public final int[] synthesize(int var1, int var2)
{
int var16;
int var15;
int var14;
int var11;
int var12;
int var13;
InstrumentDefinition.method3854(samples, 0, var1);
if (var2 < 10)
{
return samples;
}
double var3 = (double) var1 / ((double) var2 + 0.0);
this.pitch.reset();
this.volume.reset();
int var5 = 0;
int var6 = 0;
int var7 = 0;
if (this.pitchModifier != null)
{
this.pitchModifier.reset();
this.pitchModifierAmplitude.reset();
var5 = (int) ((double) (this.pitchModifier.end - this.pitchModifier.start) * 32.768 / var3);
var6 = (int) ((double) this.pitchModifier.start * 32.768 / var3);
}
int var8 = 0;
int var9 = 0;
int var10 = 0;
if (this.volumeMultiplier != null)
{
this.volumeMultiplier.reset();
this.volumeMultiplierAmplitude.reset();
var8 = (int) ((double) (this.volumeMultiplier.end - this.volumeMultiplier.start) * 32.768 / var3);
var9 = (int) ((double) this.volumeMultiplier.start * 32.768 / var3);
}
for (var11 = 0; var11 < 5; ++var11)
{
if (this.oscillatorVolume[var11] == 0)
{
continue;
}
InstrumentDefinition.phases[var11] = 0;
InstrumentDefinition.delays[var11] = (int) ((double) this.oscillatorDelays[var11] * var3);
InstrumentDefinition.volumeSteps[var11] = (this.oscillatorVolume[var11] << 14) / 100;
InstrumentDefinition.pitchSteps[var11] = (int) ((double) (this.pitch.end - this.pitch.start) * 32.768 * Math.pow(1.0057929410678534, this.oscillatorPitch[var11]) / var3);
InstrumentDefinition.pitchBaseSteps[var11] = (int) ((double) this.pitch.start * 32.768 / var3);
}
for (var11 = 0; var11 < var1; ++var11)
{
var12 = this.pitch.step(var1);
var13 = this.volume.step(var1);
if (this.pitchModifier != null)
{
var14 = this.pitchModifier.step(var1);
var15 = this.pitchModifierAmplitude.step(var1);
var12 += this.evaluateWave(var7, var15, this.pitchModifier.form) >> 1;
var7 = var7 + var6 + (var14 * var5 >> 16);
}
if (this.volumeMultiplier != null)
{
var14 = this.volumeMultiplier.step(var1);
var15 = this.volumeMultiplierAmplitude.step(var1);
var13 = var13 * ((this.evaluateWave(var10, var15, this.volumeMultiplier.form) >> 1) + 32768) >> 15;
var10 = var10 + var9 + (var14 * var8 >> 16);
}
for (var14 = 0; var14 < 5; ++var14)
{
if (this.oscillatorVolume[var14] == 0 || (var15 = delays[var14] + var11) >= var1)
{
continue;
}
int[] arrn = samples;
int n = var15;
arrn[n] = arrn[n] + this.evaluateWave(phases[var14], var13 * volumeSteps[var14] >> 15, this.pitch.form);
int[] arrn2 = phases;
int n2 = var14;
arrn2[n2] = arrn2[n2] + ((var12 * pitchSteps[var14] >> 16) + pitchBaseSteps[var14]);
}
}
if (this.release != null)
{
this.release.reset();
this.field1175.reset();
var11 = 0;
boolean var20 = true;
for (var14 = 0; var14 < var1; ++var14)
{
var15 = this.release.step(var1);
var16 = this.field1175.step(var1);
var12 = var20 ? (var15 * (this.release.end - this.release.start) >> 8) + this.release.start : (var16 * (this.release.end - this.release.start) >> 8) + this.release.start;
if ((var11 += 256) >= var12)
{
var11 = 0;
}
if (!var20)
{
continue;
}
InstrumentDefinition.samples[var14] = 0;
}
}
if (this.delayTime > 0 && this.delayDecay > 0)
{
for (var12 = var11 = (int) ((double) this.delayTime * var3); var12 < var1; ++var12)
{
int[] arrn = samples;
int n = var12;
arrn[n] = arrn[n] + samples[var12 - var11] * this.delayDecay / 100;
}
}
if (this.filter.pairs[0] > 0 || this.filter.pairs[1] > 0)
{
this.filterEnvelope.reset();
var11 = this.filterEnvelope.step(var1 + 1);
var12 = this.filter.compute(0, (float) var11 / 65536.0f);
var13 = this.filter.compute(1, (float) var11 / 65536.0f);
if (var1 >= var12 + var13)
{
int var17;
var14 = 0;
var15 = var13;
if (var13 > var1 - var12)
{
var15 = var1 - var12;
}
while (var14 < var15)
{
var16 = (int) ((long) samples[var14 + var12] * (long) SoundEffectDefinition.fowardMultiplier >> 16);
for (var17 = 0; var17 < var12; ++var17)
{
var16 += (int) ((long) samples[var14 + var12 - 1 - var17] * (long) SoundEffectDefinition.coefficients[0][var17] >> 16);
}
for (var17 = 0; var17 < var14; ++var17)
{
var16 -= (int) ((long) samples[var14 - 1 - var17] * (long) SoundEffectDefinition.coefficients[1][var17] >> 16);
}
InstrumentDefinition.samples[var14] = var16;
var11 = this.filterEnvelope.step(var1 + 1);
++var14;
}
var15 = 128;
do
{
int var18;
if (var15 > var1 - var12)
{
var15 = var1 - var12;
}
while (var14 < var15)
{
var17 = (int) ((long) samples[var14 + var12] * (long) SoundEffectDefinition.fowardMultiplier >> 16);
for (var18 = 0; var18 < var12; ++var18)
{
var17 += (int) ((long) samples[var14 + var12 - 1 - var18] * (long) SoundEffectDefinition.coefficients[0][var18] >> 16);
}
for (var18 = 0; var18 < var13; ++var18)
{
var17 -= (int) ((long) samples[var14 - 1 - var18] * (long) SoundEffectDefinition.coefficients[1][var18] >> 16);
}
InstrumentDefinition.samples[var14] = var17;
var11 = this.filterEnvelope.step(var1 + 1);
++var14;
}
if (var14 >= var1 - var12)
{
while (var14 < var1)
{
var17 = 0;
for (var18 = var14 + var12 - var1; var18 < var12; ++var18)
{
var17 += (int) ((long) samples[var14 + var12 - 1 - var18]
* (long) SoundEffectDefinition.coefficients[0][var18] >> 16);
}
for (var18 = 0; var18 < var13; ++var18)
{
var17 -= (int) ((long) samples[var14 - 1 - var18]
* (long) SoundEffectDefinition.coefficients[1][var18] >> 16);
}
InstrumentDefinition.samples[var14] = var17;
this.filterEnvelope.step(var1 + 1);
++var14;
}
break;
}
var12 = this.filter.compute(0, (float) var11 / 65536.0f);
var13 = this.filter.compute(1, (float) var11 / 65536.0f);
var15 += 128;
}
while (true);
}
}
for (var11 = 0; var11 < var1; ++var11)
{
if (samples[var11] < -32768)
{
InstrumentDefinition.samples[var11] = -32768;
}
if (samples[var11] <= 32767)
{
continue;
}
InstrumentDefinition.samples[var11] = 32767;
}
return samples;
}
private static void method3854(int[] var1, int var2, int var3)
{
var3 = var3 + var2 - 7;
while (var2 < var3)
{
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
var1[var2++] = 0;
}
while (var2 < (var3 += 7))
{
var1[var2++] = 0;
}
}
public final int evaluateWave(int var1, int var2, int var3)
{
return var3 == 1 ? ((var1 & 32767) < 16384 ? var2 : -var2) : (var3 == 2 ? AUDIO_SINE[var1 & 32767] * var2 >> 14 : (var3 == 3 ? (var2 * (var1 & 32767) >> 14) - var2 : (var3 == 4 ? var2 * NOISE[var1 / 2607 & 32767] : 0)));
}
}

View File

@@ -26,7 +26,102 @@ package net.runelite.cache.definitions.sound;
public class SoundEffectDefinition public class SoundEffectDefinition
{ {
public int field1006; public int[][][] phases = new int[2][2][4];
public SoundEffect1Definition[] field1008 = new SoundEffect1Definition[10]; public int[] pairs = new int[2];
public int field1009; public int[] unity = new int[2];
} public int[][][] magnitudes = new int[2][2][4];
public static float[][] minCoefficients = new float[2][8];
public static int[][] coefficients = new int[2][8];
public static float fowardMinCoefficientMultiplier;
public static int fowardMultiplier;
public int compute(int var1, float var2)
{
float var3;
int var4;
if (var1 == 0)
{
var3 = (float) this.unity[0] + (float) (this.unity[1] - this.unity[0]) * var2;
fowardMinCoefficientMultiplier = (float) Math.pow(0.1, (var3 *= 0.0030517578f) / 20.0f);
fowardMultiplier = (int) (fowardMinCoefficientMultiplier * 65536.0f);
}
if (this.pairs[var1] == 0)
{
return 0;
}
var3 = this.interpolateMagniture(var1, 0, var2);
minCoefficients[var1][0] = -2.0f * var3 * (float) Math.cos(this.interpolatePhase(var1, 0, var2));
minCoefficients[var1][1] = var3 * var3;
for (var4 = 1; var4 < this.pairs[var1]; ++var4)
{
var3 = this.interpolateMagniture(var1, var4, var2);
float var5 = -2.0f * var3 * (float) Math.cos(this.interpolatePhase(var1, var4, var2));
float var6 = var3 * var3;
minCoefficients[var1][var4 * 2 + 1] = minCoefficients[var1][var4 * 2 - 1] * var6;
minCoefficients[var1][var4 * 2] = minCoefficients[var1][var4 * 2 - 1] * var5 + minCoefficients[var1][var4 * 2 - 2] * var6;
for (int var7 = var4 * 2 - 1; var7 >= 2; --var7)
{
float[] arrf = minCoefficients[var1];
int n = var7;
arrf[n] = arrf[n] + (minCoefficients[var1][var7 - 1] * var5 + minCoefficients[var1][var7 - 2] * var6);
}
float[] arrf = minCoefficients[var1];
arrf[1] = arrf[1] + (minCoefficients[var1][0] * var5 + var6);
float[] arrf2 = minCoefficients[var1];
arrf2[0] = arrf2[0] + var5;
}
if (var1 == 0)
{
var4 = 0;
while (var4 < this.pairs[0] * 2)
{
float[] arrf = minCoefficients[0];
int n = var4++;
arrf[n] = arrf[n] * fowardMinCoefficientMultiplier;
}
}
for (var4 = 0; var4 < this.pairs[var1] * 2; ++var4)
{
coefficients[var1][var4] = (int) (minCoefficients[var1][var4] * 65536.0f);
}
return this.pairs[var1] * 2;
}
public float interpolateMagniture(int var1, int var2, float var3)
{
float var4 = (float) this.magnitudes[var1][0][var2] + var3 * (float) (this.magnitudes[var1][1][var2] - this.magnitudes[var1][0][var2]);
return 1.0f - (float) Math.pow(10.0, (-(var4 *= 0.0015258789f)) / 20.0f);
}
public float interpolatePhase(int var1, int var2, float var3)
{
float var4 = (float) this.phases[var1][0][var2] + var3 * (float) (this.phases[var1][1][var2] - this.phases[var1][0][var2]);
return normalise(var4 *= 1.2207031E-4f);
}
public static float normalise(float var1)
{
float var2 = 32.703197f * (float) Math.pow(2.0, var1);
return var2 * 3.1415927f / 11025.0f;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.cache.definitions.sound;
public class SoundEffectTrackDefinition
{
public int start;
public InstrumentDefinition[] instruments = new InstrumentDefinition[10];
public int end;
public final byte[] mix()
{
int var2;
int var1 = 0;
for (var2 = 0; var2 < 10; ++var2)
{
if (this.instruments[var2] == null || this.instruments[var2].duration + this.instruments[var2].offset <= var1)
{
continue;
}
var1 = this.instruments[var2].duration + this.instruments[var2].offset;
}
if (var1 == 0)
{
return new byte[0];
}
var2 = var1 * 22050 / 1000;
byte[] var3 = new byte[var2];
for (int i = 0; i < 10; ++i)
{
if (this.instruments[i] == null)
{
continue;
}
int var5 = this.instruments[i].duration * 22050 / 1000;
int var6 = this.instruments[i].offset * 22050 / 1000;
int[] var7 = this.instruments[i].synthesize(var5, this.instruments[i].duration);
for (int j = 0; j < var5; ++j)
{
int var9 = (var7[j] >> 8) + var3[j + var6];
if ((var9 + 128 & -256) != 0)
{
var9 = var9 >> 31 ^ 127;
}
var3[j + var6] = (byte) var9;
}
}
return var3;
}
}

View File

@@ -27,11 +27,16 @@ package net.runelite.cache;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import net.runelite.cache.definitions.loaders.sound.SoundEffectLoader; import net.runelite.cache.definitions.loaders.sound.SoundEffectTrackLoader;
import net.runelite.cache.definitions.sound.SoundEffectDefinition; import net.runelite.cache.definitions.sound.SoundEffectTrackDefinition;
import net.runelite.cache.fs.Archive; import net.runelite.cache.fs.Archive;
import net.runelite.cache.fs.Index; import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage; import net.runelite.cache.fs.Storage;
@@ -42,6 +47,11 @@ import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class SoundEffectsDumperTest public class SoundEffectsDumperTest
{ {
private static final Logger logger = LoggerFactory.getLogger(SoundEffectsDumperTest.class); private static final Logger logger = LoggerFactory.getLogger(SoundEffectsDumperTest.class);
@@ -68,14 +78,68 @@ public class SoundEffectsDumperTest
{ {
byte[] contents = archive.decompress(storage.loadArchive(archive)); byte[] contents = archive.decompress(storage.loadArchive(archive));
SoundEffectLoader soundEffectLoader = new SoundEffectLoader(); SoundEffectTrackLoader setLoader = new SoundEffectTrackLoader();
SoundEffectDefinition soundEffect = soundEffectLoader.load(contents); SoundEffectTrackDefinition soundEffect = setLoader.load(contents);
Files.asCharSink(new File(dumpDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()).write(gson.toJson(soundEffect)); Files.write(gson.toJson(soundEffect), new File(dumpDir, archive.getArchiveId() + ".json"), Charset.defaultCharset());
++count; ++count;
} }
} }
logger.info("Dumped {} sound effects to {}", count, dumpDir); logger.info("Dumped {} sound effects to {}", count, dumpDir);
} }
}
@Test
public void extractWavTest() throws IOException
{
File dumpDir = folder.newFolder();
int count = 0;
try (Store store = new Store(StoreLocation.LOCATION))
{
store.load();
Storage storage = store.getStorage();
Index index = store.getIndex(IndexType.SOUNDEFFECTS);
for (Archive archive : index.getArchives())
{
byte[] contents = archive.decompress(storage.loadArchive(archive));
SoundEffectTrackLoader setLoader = new SoundEffectTrackLoader();
SoundEffectTrackDefinition soundEffect = setLoader.load(contents);
try
{
Object audioStream;
byte[] data = soundEffect.mix();
AudioFormat audioFormat = new AudioFormat(22050.0f, 8, 1, true, false);
audioStream = new AudioInputStream(new ByteArrayInputStream(data), audioFormat, data.length);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
AudioSystem.write((AudioInputStream) audioStream, AudioFileFormat.Type.WAVE, bos);
data = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(new File(dumpDir, archive.getArchiveId() + ".wav"));
try
{
fos.write(data);
}
finally
{
fos.close();
}
++count;
}
catch (Exception e)
{
continue;
}
}
}
logger.info("Dumped {} sound effects to {}", count, dumpDir);
}
}

View File

@@ -50,7 +50,7 @@
<mockito.version>1.10.19</mockito.version> <mockito.version>1.10.19</mockito.version>
<sql2o.version>1.6.0</sql2o.version> <sql2o.version>1.6.0</sql2o.version>
<minio.version>3.0.6</minio.version> <minio.version>3.0.6</minio.version>
<okhttp3.version>4.0.0</okhttp3.version> <okhttp3.version>3.14.0</okhttp3.version>
<zlika.reproducible.build.maven.plugin.version>0.7</zlika.reproducible.build.maven.plugin.version> <zlika.reproducible.build.maven.plugin.version>0.7</zlika.reproducible.build.maven.plugin.version>
<maven.jar.plugin.version>3.1.2</maven.jar.plugin.version> <maven.jar.plugin.version>3.1.2</maven.jar.plugin.version>

View File

@@ -197,6 +197,7 @@ public final class AnimationID
public static final int FARMING_PLANT_SEED = 2291; public static final int FARMING_PLANT_SEED = 2291;
public static final int FARMING_HARVEST_FLOWER = 2292; public static final int FARMING_HARVEST_FLOWER = 2292;
public static final int FARMING_MIX_ULTRACOMPOST = 7699; public static final int FARMING_MIX_ULTRACOMPOST = 7699;
public static final int FARMING_HARVEST_ALLOTMENT = 830;
// Lunar spellbook // Lunar spellbook
public static final int ENERGY_TRANSFER_VENGEANCE_OTHER = 4411; public static final int ENERGY_TRANSFER_VENGEANCE_OTHER = 4411;
@@ -315,7 +316,7 @@ public final class AnimationID
public static final int DAG_SUPREME = 2855; public static final int DAG_SUPREME = 2855;
// Lizardman shaman // Lizardman shaman
public static final int LIZARDMAN_SHAMAN_SPAWN = 2855; public static final int LIZARDMAN_SHAMAN_SPAWN = 7157;
// Combat counter // Combat counter
public static final int BARRAGE_ANIMATION = 1979; public static final int BARRAGE_ANIMATION = 1979;

View File

@@ -1353,6 +1353,20 @@ public interface Client extends GameShell
*/ */
void setInterpolateObjectAnimations(boolean interpolate); void setInterpolateObjectAnimations(boolean interpolate);
/**
* Checks whether animation smoothing is enabled for widgets.
*
* @return true if widget animation smoothing is enabled, false otherwise
*/
boolean isInterpolateWidgetAnimations();
/**
* Sets the animation smoothing state for widgets.
*
* @param interpolate the new smoothing state
*/
void setInterpolateWidgetAnimations(boolean interpolate);
/** /**
* Checks whether the logged in player is in an instanced region. * Checks whether the logged in player is in an instanced region.
* *

View File

@@ -82,4 +82,16 @@ public enum InventoryID
{ {
return id; return id;
} }
public static InventoryID getValue(int value)
{
for (InventoryID e: InventoryID.values())
{
if (e.id == value)
{
return e;
}
}
return null;
}
} }

View File

@@ -28,7 +28,7 @@ import net.runelite.api.ItemContainer;
import lombok.Value; import lombok.Value;
/** /**
* An event called whenever the stack size of an {@link api.Item} * An event called whenever the stack size of an {@link net.runelite.api.Item}
* in an {@link ItemContainer} is modified. * in an {@link ItemContainer} is modified.
* <p> * <p>
* Examples of when this event may trigger include: * Examples of when this event may trigger include:
@@ -41,6 +41,11 @@ import lombok.Value;
@Value @Value
public class ItemContainerChanged public class ItemContainerChanged
{ {
/**
* The modified container's ID.
*/
private final int containerId;
/** /**
* The modified item container. * The modified item container.
*/ */

View File

@@ -290,6 +290,16 @@
<version>3.2.0</version> <version>3.2.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.11</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.9</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -385,6 +385,18 @@ public class ItemManager
* @return item price * @return item price
*/ */
public int getItemPrice(int itemID) public int getItemPrice(int itemID)
{
return getItemPrice(itemID, false);
}
/**
* Look up an item's price
*
* @param itemID item id
* @param ignoreUntradeableMap should the price returned ignore the {@link UntradeableItemMapping}
* @return item price
*/
public int getItemPrice(int itemID, boolean ignoreUntradeableMap)
{ {
if (itemID == ItemID.COINS_995) if (itemID == ItemID.COINS_995)
{ {
@@ -395,10 +407,13 @@ public class ItemManager
return 1000; return 1000;
} }
UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID)); if (!ignoreUntradeableMap)
if (p != null)
{ {
return getItemPrice(p.getPriceID()) * p.getQuantity(); UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID));
if (p != null)
{
return getItemPrice(p.getPriceID()) * p.getQuantity();
}
} }
int price = 0; int price = 0;

View File

@@ -41,6 +41,7 @@ import java.nio.file.WatchService;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
@@ -154,7 +155,6 @@ public class PluginWatcher extends Thread
{ {
continue; continue;
} }
log.info("Loading plugin from {}", file); log.info("Loading plugin from {}", file);
load(file); load(file);
} }

View File

@@ -65,4 +65,14 @@ public interface AnimationSmoothingConfig extends Config
return true; return true;
} }
@ConfigItem(
keyName = "smoothWidgetAnimations",
name = "Smooth Widget Animations",
description = "Configures whether the widget animations are smooth or not",
position = 4
)
default boolean smoothWidgetAnimations()
{
return true;
}
} }

View File

@@ -69,6 +69,7 @@ public class AnimationSmoothingPlugin extends Plugin
client.setInterpolatePlayerAnimations(false); client.setInterpolatePlayerAnimations(false);
client.setInterpolateNpcAnimations(false); client.setInterpolateNpcAnimations(false);
client.setInterpolateObjectAnimations(false); client.setInterpolateObjectAnimations(false);
client.setInterpolateWidgetAnimations(false);
} }
@Subscribe @Subscribe
@@ -85,5 +86,6 @@ public class AnimationSmoothingPlugin extends Plugin
client.setInterpolatePlayerAnimations(config.smoothPlayerAnimations()); client.setInterpolatePlayerAnimations(config.smoothPlayerAnimations());
client.setInterpolateNpcAnimations(config.smoothNpcAnimations()); client.setInterpolateNpcAnimations(config.smoothNpcAnimations());
client.setInterpolateObjectAnimations(config.smoothObjectAnimations()); client.setInterpolateObjectAnimations(config.smoothObjectAnimations());
client.setInterpolateWidgetAnimations(config.smoothWidgetAnimations());
} }
} }

View File

@@ -57,7 +57,8 @@ enum Boss
KRAKEN(NpcID.KRAKEN, 8400, ChronoUnit.MILLIS, ItemID.PET_KRAKEN), KRAKEN(NpcID.KRAKEN, 8400, ChronoUnit.MILLIS, ItemID.PET_KRAKEN),
KALPHITE_QUEEN(NpcID.KALPHITE_QUEEN_965, 30, ChronoUnit.SECONDS, ItemID.KALPHITE_PRINCESS), KALPHITE_QUEEN(NpcID.KALPHITE_QUEEN_965, 30, ChronoUnit.SECONDS, ItemID.KALPHITE_PRINCESS),
DUSK(NpcID.DUSK_7889, 2, ChronoUnit.MINUTES, ItemID.NOON), DUSK(NpcID.DUSK_7889, 2, ChronoUnit.MINUTES, ItemID.NOON),
ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA_8622, 25200, ChronoUnit.MILLIS, ItemID.IKKLE_HYDRA); ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA_8622, 25200, ChronoUnit.MILLIS, ItemID.IKKLE_HYDRA),
SARACHNIS(NpcID.SARACHNIS, 30, ChronoUnit.SECONDS, ItemID.SRARACHA);
private static final Map<Integer, Boss> bosses; private static final Map<Integer, Boss> bosses;

View File

@@ -86,4 +86,15 @@ public interface ChatFilterConfig extends Config
{ {
return false; return false;
} }
@ConfigItem(
keyName = "filterLogin",
name = "Filter Logged In/Out Messages",
description = "Filter your private chat to remove logged in/out messages",
position = 6
)
default boolean filterLogin()
{
return false;
}
} }

View File

@@ -133,6 +133,13 @@ public class ChatFilterPlugin extends Plugin
case FRIENDSCHAT: case FRIENDSCHAT:
case GAMEMESSAGE: case GAMEMESSAGE:
break; break;
case LOGINLOGOUTNOTIFICATION:
if (config.filterLogin())
{
// Block the message
intStack[intStackSize - 3] = 0;
}
return;
default: default:
return; return;
} }

View File

@@ -25,11 +25,14 @@
package net.runelite.client.plugins.config; package net.runelite.client.plugins.config;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.lang.reflect.Method;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import net.runelite.api.MenuAction; import net.runelite.api.MenuAction;
import net.runelite.client.RuneLite;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ChatColorConfig; import net.runelite.client.config.ChatColorConfig;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.config.RuneLiteConfig;
@@ -41,6 +44,7 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginManager; import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayMenuEntry;
@@ -97,9 +101,25 @@ public class ConfigPlugin extends Plugin
} }
@Override @Override
protected void shutDown() throws Exception public void shutDown() throws Exception
{ {
clientToolbar.removeNavigation(navButton); clientToolbar.removeNavigation(navButton);
RuneLite.getInjector().getInstance(ClientThread.class).invokeLater(() ->
{
try
{
ConfigPanel.pluginList.clear();
pluginManager.setPluginEnabled(this, true);
pluginManager.startPlugin(this);
Method expand = ClientUI.class.getDeclaredMethod("expand", NavigationButton.class);
expand.setAccessible(true);
expand.invoke(RuneLite.getInjector().getInstance(ClientUI.class), navButton);
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
});
} }
@Subscribe @Subscribe

View File

@@ -253,7 +253,12 @@ public class IdleNotifierPlugin extends Plugin
case USING_GILDED_ALTAR: case USING_GILDED_ALTAR:
/* Farming */ /* Farming */
case FARMING_MIX_ULTRACOMPOST: case FARMING_MIX_ULTRACOMPOST:
/* Misc */ case FARMING_HARVEST_BUSH:
case FARMING_HARVEST_HERB:
case FARMING_HARVEST_FRUIT_TREE:
case FARMING_HARVEST_FLOWER:
case FARMING_HARVEST_ALLOTMENT:
/* Misc */
case PISCARILIUS_CRANE_REPAIR: case PISCARILIUS_CRANE_REPAIR:
case HOME_MAKE_TABLET: case HOME_MAKE_TABLET:
case SAND_COLLECTION: case SAND_COLLECTION:

View File

@@ -69,7 +69,7 @@ class InventoryGridOverlay extends Overlay
final Widget if1DraggingWidget = client.getIf1DraggedWidget(); final Widget if1DraggingWidget = client.getIf1DraggedWidget();
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY); final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
if (if1DraggingWidget == null || if1DraggingWidget.equals(inventoryWidget) if (if1DraggingWidget == null || if1DraggingWidget != inventoryWidget
|| client.getItemPressedDuration() < plugin.getDragDelay() / Constants.CLIENT_TICK_LENGTH) || client.getItemPressedDuration() < plugin.getDragDelay() / Constants.CLIENT_TICK_LENGTH)
{ {
return null; return null;

View File

@@ -42,7 +42,9 @@ enum AlwaysLostItem
{ {
RUNE_POUCH(ItemID.RUNE_POUCH, true), RUNE_POUCH(ItemID.RUNE_POUCH, true),
LOOTING_BAG(ItemID.LOOTING_BAG, false), LOOTING_BAG(ItemID.LOOTING_BAG, false),
CLUE_BOX(ItemID.CLUE_BOX, false); CLUE_BOX(ItemID.CLUE_BOX, false),
BRACELET_OF_ETHEREUM(ItemID.BRACELET_OF_ETHEREUM, false),
BRACELET_OF_ETHEREUM_UNCHARGED(ItemID.BRACELET_OF_ETHEREUM_UNCHARGED, false);
private final int itemID; private final int itemID;
private final boolean keptOutsideOfWilderness; private final boolean keptOutsideOfWilderness;

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.itemskeptondeath;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
/**
* Degradable/Non-rechargeable Jewelry death prices are usually determined by the amount of charges the item has left.
* The price of each charge is based on the GE price of the fully charged item divided by the maximum item charges
* Charge price = GE Price / Max Charges
* Death Price = Charge price * Current Charges
*/
@AllArgsConstructor
@Getter
enum DynamicPriceItem
{
GAMES_NECKLACE1(ItemID.GAMES_NECKLACE1, 1, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE2(ItemID.GAMES_NECKLACE2, 2, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE3(ItemID.GAMES_NECKLACE3, 3, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE4(ItemID.GAMES_NECKLACE4, 4, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE5(ItemID.GAMES_NECKLACE5, 5, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE6(ItemID.GAMES_NECKLACE6, 6, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE7(ItemID.GAMES_NECKLACE7, 7, 8, ItemID.GAMES_NECKLACE8),
RING_OF_DUELING1(ItemID.RING_OF_DUELING1, 1, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING2(ItemID.RING_OF_DUELING2, 2, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING3(ItemID.RING_OF_DUELING3, 3, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING4(ItemID.RING_OF_DUELING4, 4, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING5(ItemID.RING_OF_DUELING5, 5, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING6(ItemID.RING_OF_DUELING6, 6, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING7(ItemID.RING_OF_DUELING7, 7, 8, ItemID.RING_OF_DUELING8),
RING_OF_RETURNING1(ItemID.RING_OF_RETURNING1, 1, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING2(ItemID.RING_OF_RETURNING2, 2, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING3(ItemID.RING_OF_RETURNING3, 3, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING4(ItemID.RING_OF_RETURNING4, 4, 5, ItemID.RING_OF_RETURNING5),
NECKLACE_OF_PASSAGE1(ItemID.NECKLACE_OF_PASSAGE1, 1, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE2(ItemID.NECKLACE_OF_PASSAGE2, 2, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE3(ItemID.NECKLACE_OF_PASSAGE3, 3, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE4(ItemID.NECKLACE_OF_PASSAGE4, 4, 5, ItemID.NECKLACE_OF_PASSAGE5),
BURNING_AMULET1(ItemID.BURNING_AMULET1, 1, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET2(ItemID.BURNING_AMULET2, 2, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET3(ItemID.BURNING_AMULET3, 3, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET4(ItemID.BURNING_AMULET4, 4, 5, ItemID.BURNING_AMULET5);
private final int itemId;
private final int currentCharges;
private final int maxCharges;
private final int chargedId;
private static final Map<Integer, DynamicPriceItem> DYNAMIC_ITEMS;
static
{
final ImmutableMap.Builder<Integer, DynamicPriceItem> map = ImmutableMap.builder();
for (final DynamicPriceItem p : values())
{
map.put(p.itemId, p);
}
DYNAMIC_ITEMS = map.build();
}
/**
* Calculates the price off the partially charged jewelry based on the base items price
* @param basePrice price of the base item, usually the trade-able variant
* @return death price of the current DynamicPriceItem
*/
int calculateDeathPrice(final int basePrice)
{
return (basePrice / maxCharges) * currentCharges;
}
@Nullable
static DynamicPriceItem find(int itemId)
{
return DYNAMIC_ITEMS.get(itemId);
}
}

View File

@@ -28,8 +28,6 @@ package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.ItemID; import net.runelite.api.ItemID;
@@ -37,8 +35,7 @@ import net.runelite.api.ItemID;
* Some items have a fixed price that is added to its default value when calculating death prices. * Some items have a fixed price that is added to its default value when calculating death prices.
* These are typically imbued items, such as Berserker ring (i), to help it protect over the non-imbued variants. * These are typically imbued items, such as Berserker ring (i), to help it protect over the non-imbued variants.
*/ */
@AllArgsConstructor @Getter
@Getter(AccessLevel.PACKAGE)
enum FixedPriceItem enum FixedPriceItem
{ {
IMBUED_BLACK_MASK_I(ItemID.BLACK_MASK_I, 5000), IMBUED_BLACK_MASK_I(ItemID.BLACK_MASK_I, 5000),
@@ -67,10 +64,161 @@ enum FixedPriceItem
IMBUED_RING_OF_THE_GODS_I(ItemID.RING_OF_THE_GODS_I, 2000), IMBUED_RING_OF_THE_GODS_I(ItemID.RING_OF_THE_GODS_I, 2000),
IMBUED_TREASONOUS_RING_I(ItemID.TREASONOUS_RING_I, 2000), IMBUED_TREASONOUS_RING_I(ItemID.TREASONOUS_RING_I, 2000),
IMBUED_TYRANNICAL_RING_I(ItemID.TYRANNICAL_RING_I, 2000); IMBUED_TYRANNICAL_RING_I(ItemID.TYRANNICAL_RING_I, 2000),
GRACEFUL_HOOD(ItemID.GRACEFUL_HOOD, 1965),
GRACEFUL_CAPE(ItemID.GRACEFUL_CAPE, 2460),
GRACEFUL_TOP(ItemID.GRACEFUL_TOP, 2345),
GRACEFUL_LEGS(ItemID.GRACEFUL_LEGS, 2290),
GRACEFUL_GLOVES(ItemID.GRACEFUL_GLOVES, 1970),
GRACEFUL_BOOTS(ItemID.GRACEFUL_BOOTS, 2060),
ANGLER_HAT(ItemID.ANGLER_HAT, 2600),
ANGLER_TOP(ItemID.ANGLER_TOP, 3550),
ANGLER_WADERS(ItemID.ANGLER_WADERS, 4400),
ANGLER_BOOTS(ItemID.ANGLER_BOOTS, 5300),
PROSPECTOR_HELMET(ItemID.PROSPECTOR_HELMET, 2640),
PROSPECTOR_JACKET(ItemID.PROSPECTOR_JACKET, 3550),
PROSPECTOR_LEGS(ItemID.PROSPECTOR_LEGS, 4460),
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 5370),
LUMBERJACK_HAT(ItemID.LUMBERJACK_HAT, 19950),
LUMBERJACK_TOP(ItemID.LUMBERJACK_TOP, 19950),
LUMBERJACK_LEGS(ItemID.LUMBERJACK_LEGS, 19950),
LUMBERJACK_BOOTS(ItemID.LUMBERJACK_BOOTS, 19950),
ROGUE_MASK(ItemID.ROGUE_MASK, 725),
ROGUE_TOP(ItemID.ROGUE_TOP, 575),
ROGUE_TROUSERS(ItemID.ROGUE_TROUSERS, 500),
ROGUE_GLOVES(ItemID.ROGUE_GLOVES, 650),
ROGUE_BOOTS(ItemID.ROGUE_BOOTS, 650),
RING_OF_WEALTH_1(ItemID.RING_OF_WEALTH_1, 500, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_2(ItemID.RING_OF_WEALTH_2, 1000, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_3(ItemID.RING_OF_WEALTH_3, 1500, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_4(ItemID.RING_OF_WEALTH_4, 2000, ItemID.RING_OF_WEALTH),
AMULET_OF_GLORY1(ItemID.AMULET_OF_GLORY1, 500, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY2(ItemID.AMULET_OF_GLORY2, 1000, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY3(ItemID.AMULET_OF_GLORY3, 1500, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY5(ItemID.AMULET_OF_GLORY5, 2500, ItemID.AMULET_OF_GLORY),
COMBAT_BRACELET1(ItemID.COMBAT_BRACELET1, 500, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET2(ItemID.COMBAT_BRACELET2, 1000, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET3(ItemID.COMBAT_BRACELET3, 1500, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET5(ItemID.COMBAT_BRACELET5, 2500, ItemID.COMBAT_BRACELET),
SKILLS_NECKLACE1(ItemID.SKILLS_NECKLACE1, 500, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE2(ItemID.SKILLS_NECKLACE2, 1000, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE3(ItemID.SKILLS_NECKLACE3, 1500, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE4(ItemID.SKILLS_NECKLACE5, 2500, ItemID.SKILLS_NECKLACE),
AHRIMS_HOOD_25(ItemID.AHRIMS_HOOD_25, 2500, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_50(ItemID.AHRIMS_HOOD_50, 5000, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_75(ItemID.AHRIMS_HOOD_75, 7500, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_100(ItemID.AHRIMS_HOOD_100, 10000, ItemID.AHRIMS_HOOD_0),
AHRIMS_ROBETOP_25(ItemID.AHRIMS_ROBETOP_25, 2500, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_50(ItemID.AHRIMS_ROBETOP_50, 5000, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_75(ItemID.AHRIMS_ROBETOP_75, 7500, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_100(ItemID.AHRIMS_ROBETOP_100, 10000, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBESKIRT_25(ItemID.AHRIMS_ROBESKIRT_25, 2500, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_50(ItemID.AHRIMS_ROBESKIRT_50, 5000, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_75(ItemID.AHRIMS_ROBESKIRT_75, 7500, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_100(ItemID.AHRIMS_ROBESKIRT_100, 10000, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_STAFF_25(ItemID.AHRIMS_STAFF_25, 2500, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_50(ItemID.AHRIMS_STAFF_50, 5000, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_75(ItemID.AHRIMS_STAFF_75, 7500, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_100(ItemID.AHRIMS_STAFF_100, 10000, ItemID.AHRIMS_STAFF_0),
KARILS_COIF_25(ItemID.KARILS_COIF_25, 2500, ItemID.KARILS_COIF_0),
KARILS_COIF_50(ItemID.KARILS_COIF_50, 5000, ItemID.KARILS_COIF_0),
KARILS_COIF_75(ItemID.KARILS_COIF_75, 7500, ItemID.KARILS_COIF_0),
KARILS_COIF_100(ItemID.KARILS_COIF_100, 10000, ItemID.KARILS_COIF_0),
KARILS_LEATHERTOP_25(ItemID.KARILS_LEATHERTOP_25, 2500, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_50(ItemID.KARILS_LEATHERTOP_50, 5000, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_75(ItemID.KARILS_LEATHERTOP_75, 7500, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_100(ItemID.KARILS_LEATHERTOP_100, 10000, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERSKIRT_25(ItemID.KARILS_LEATHERSKIRT_25, 2500, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_50(ItemID.KARILS_LEATHERSKIRT_50, 5000, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_75(ItemID.KARILS_LEATHERSKIRT_75, 7500, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_100(ItemID.KARILS_LEATHERSKIRT_100, 10000, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_CROSSBOW_25(ItemID.KARILS_CROSSBOW_25, 2500, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_50(ItemID.KARILS_CROSSBOW_50, 5000, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_75(ItemID.KARILS_CROSSBOW_75, 7500, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_100(ItemID.KARILS_CROSSBOW_100, 10000, ItemID.KARILS_CROSSBOW_0),
DHAROKS_HELM_25(ItemID.DHAROKS_HELM_25, 2500, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_50(ItemID.DHAROKS_HELM_50, 5000, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_75(ItemID.DHAROKS_HELM_75, 7500, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_100(ItemID.DHAROKS_HELM_100, 10000, ItemID.DHAROKS_HELM_0),
DHAROKS_PLATEBODY_25(ItemID.DHAROKS_PLATEBODY_25, 2500, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_50(ItemID.DHAROKS_PLATEBODY_50, 5000, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_75(ItemID.DHAROKS_PLATEBODY_75, 7500, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_100(ItemID.DHAROKS_PLATEBODY_100, 10000, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATELEGS_25(ItemID.DHAROKS_PLATELEGS_25, 2500, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_50(ItemID.DHAROKS_PLATELEGS_50, 5000, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_75(ItemID.DHAROKS_PLATELEGS_75, 7500, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_100(ItemID.DHAROKS_PLATELEGS_100, 10000, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_GREATAXE_25(ItemID.DHAROKS_GREATAXE_25, 2500, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_50(ItemID.DHAROKS_GREATAXE_50, 5000, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_75(ItemID.DHAROKS_GREATAXE_75, 7500, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_100(ItemID.DHAROKS_GREATAXE_100, 10000, ItemID.DHAROKS_GREATAXE_0),
GUTHANS_HELM_25(ItemID.GUTHANS_HELM_25, 2500, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_50(ItemID.GUTHANS_HELM_50, 5000, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_75(ItemID.GUTHANS_HELM_75, 7500, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_100(ItemID.GUTHANS_HELM_100, 10000, ItemID.GUTHANS_HELM_0),
GUTHANS_PLATEBODY_25(ItemID.GUTHANS_PLATEBODY_25, 2500, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_50(ItemID.GUTHANS_PLATEBODY_50, 5000, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_75(ItemID.GUTHANS_PLATEBODY_75, 7500, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_100(ItemID.GUTHANS_PLATEBODY_100, 10000, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_CHAINSKIRT_25(ItemID.GUTHANS_CHAINSKIRT_25, 2500, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_50(ItemID.GUTHANS_CHAINSKIRT_50, 5000, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_75(ItemID.GUTHANS_CHAINSKIRT_75, 7500, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_100(ItemID.GUTHANS_CHAINSKIRT_100, 10000, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_WARSPEAR_25(ItemID.GUTHANS_WARSPEAR_25, 2500, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_50(ItemID.GUTHANS_WARSPEAR_50, 5000, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_75(ItemID.GUTHANS_WARSPEAR_75, 7500, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_100(ItemID.GUTHANS_WARSPEAR_100, 10000, ItemID.GUTHANS_WARSPEAR_0),
TORAGS_HELM_25(ItemID.TORAGS_HELM_25, 2500, ItemID.TORAGS_HELM_0),
TORAGS_HELM_50(ItemID.TORAGS_HELM_50, 5000, ItemID.TORAGS_HELM_0),
TORAGS_HELM_75(ItemID.TORAGS_HELM_75, 7500, ItemID.TORAGS_HELM_0),
TORAGS_HELM_100(ItemID.TORAGS_HELM_100, 10000, ItemID.TORAGS_HELM_0),
TORAGS_PLATEBODY_25(ItemID.TORAGS_PLATEBODY_25, 2500, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_50(ItemID.TORAGS_PLATEBODY_50, 5000, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_75(ItemID.TORAGS_PLATEBODY_75, 7500, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_100(ItemID.TORAGS_PLATEBODY_100, 10000, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATELEGS_25(ItemID.TORAGS_PLATELEGS_25, 2500, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_50(ItemID.TORAGS_PLATELEGS_50, 5000, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_75(ItemID.TORAGS_PLATELEGS_75, 7500, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_100(ItemID.TORAGS_PLATELEGS_100, 10000, ItemID.TORAGS_PLATELEGS_0),
TORAGS_HAMMERS_25(ItemID.TORAGS_HAMMERS_25, 2500, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_50(ItemID.TORAGS_HAMMERS_50, 5000, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_75(ItemID.TORAGS_HAMMERS_75, 7500, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_100(ItemID.TORAGS_HAMMERS_100, 10000, ItemID.TORAGS_HAMMERS_0),
VERACS_HELM_25(ItemID.VERACS_HELM_25, 2500, ItemID.VERACS_HELM_0),
VERACS_HELM_50(ItemID.VERACS_HELM_50, 5000, ItemID.VERACS_HELM_0),
VERACS_HELM_75(ItemID.VERACS_HELM_75, 7500, ItemID.VERACS_HELM_0),
VERACS_HELM_100(ItemID.VERACS_HELM_100, 10000, ItemID.VERACS_HELM_0),
VERACS_BRASSARD_25(ItemID.VERACS_BRASSARD_25, 2500, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_50(ItemID.VERACS_BRASSARD_50, 5000, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_75(ItemID.VERACS_BRASSARD_75, 7500, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_100(ItemID.VERACS_BRASSARD_100, 10000, ItemID.VERACS_BRASSARD_0),
VERACS_PLATESKIRT_25(ItemID.VERACS_PLATESKIRT_25, 2500, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_50(ItemID.VERACS_PLATESKIRT_50, 5000, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_75(ItemID.VERACS_PLATESKIRT_75, 7500, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_100(ItemID.VERACS_PLATESKIRT_100, 10000, ItemID.VERACS_PLATESKIRT_0),
VERACS_FLAIL_25(ItemID.VERACS_FLAIL_25, 2500, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_50(ItemID.VERACS_FLAIL_50, 5000, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_75(ItemID.VERACS_FLAIL_75, 7500, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_100(ItemID.VERACS_FLAIL_100, 10000, ItemID.VERACS_FLAIL_0);
private final int itemId; private final int itemId;
private final int offset; private final int offset;
private final int baseId;
private static final Map<Integer, FixedPriceItem> FIXED_ITEMS; private static final Map<Integer, FixedPriceItem> FIXED_ITEMS;
@@ -84,6 +232,18 @@ enum FixedPriceItem
FIXED_ITEMS = map.build(); FIXED_ITEMS = map.build();
} }
FixedPriceItem(final int itemId, final int offset, final int baseId)
{
this.itemId = itemId;
this.offset = offset;
this.baseId = baseId;
}
FixedPriceItem(final int itemId, final int offset)
{
this(itemId, offset, -1);
}
@Nullable @Nullable
static FixedPriceItem find(int itemId) static FixedPriceItem find(int itemId)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Adam <Adam@sigterm.info> * Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,12 +22,15 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.cache.definitions.sound; package net.runelite.client.plugins.itemskeptondeath;
public class SoundEffect3Definition import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
class ItemStack
{ {
public int[][][] field1154 = new int[2][2][4]; private int id;
public int[] field1155 = new int[2]; private int qty;
public int[] field1156 = new int[2];
public int[][][] field1159 = new int[2][2][4];
} }

View File

@@ -25,6 +25,7 @@
*/ */
package net.runelite.client.plugins.itemskeptondeath; package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@@ -32,8 +33,11 @@ import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Constants; import net.runelite.api.Constants;
@@ -55,6 +59,7 @@ import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetType; import net.runelite.api.widgets.WidgetType;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemMapping;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.StackFormatter; import net.runelite.client.util.StackFormatter;
@@ -71,6 +76,16 @@ public class ItemsKeptOnDeathPlugin extends Plugin
private static final int DEEP_WILDY = 20; private static final int DEEP_WILDY = 20;
private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+).*"); private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+).*");
@AllArgsConstructor
@Getter
@VisibleForTesting
static class DeathItems
{
private final List<ItemStack> keptItems;
private final List<ItemStack> lostItems;
private final boolean hasAlwaysLost;
}
// Item Container helpers // Item Container helpers
private static final int MAX_ROW_ITEMS = 8; private static final int MAX_ROW_ITEMS = 8;
private static final int ITEM_X_OFFSET = 5; private static final int ITEM_X_OFFSET = 5;
@@ -100,9 +115,12 @@ public class ItemsKeptOnDeathPlugin extends Plugin
private WidgetButton deepWildyButton; private WidgetButton deepWildyButton;
private WidgetButton lowWildyButton; private WidgetButton lowWildyButton;
private boolean isSkulled; @VisibleForTesting
private boolean protectingItem; boolean isSkulled;
private int wildyLevel; @VisibleForTesting
boolean protectingItem;
@VisibleForTesting
int wildyLevel;
@Subscribe @Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent event) public void onScriptCallbackEvent(ScriptCallbackEvent event)
@@ -225,97 +243,12 @@ public class ItemsKeptOnDeathPlugin extends Plugin
final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
final Item[] equip = equipment == null ? new Item[0] : equipment.getItems(); final Item[] equip = equipment == null ? new Item[0] : equipment.getItems();
final List<Item> items = new ArrayList<>(); final DeathItems deathItems = calculateKeptLostItems(inv, equip);
Collections.addAll(items, inv);
Collections.addAll(items, equip);
// Sort by item price final List<Widget> keptItems = deathItems.getKeptItems().stream()
items.sort(Comparator.comparing(this::getDeathPrice).reversed()); .map(item -> createItemWidget(kept, item, true)).collect(Collectors.toList());
final List<Widget> lostItems = deathItems.getLostItems().stream()
boolean hasAlwaysLost = false; .map(item -> createItemWidget(lost, item, false)).collect(Collectors.toList());
int keepCount = getDefaultItemsKept();
final List<Widget> keptItems = new ArrayList<>();
final List<Widget> lostItems = new ArrayList<>();
for (final Item i : items)
{
final int id = i.getId();
int itemQuantity = i.getQuantity();
if (id == -1)
{
continue;
}
final ItemDefinition c = itemManager.getItemDefinition(i.getId());
// Bonds are always kept and do not count towards the limit.
if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE)
{
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
keptItems.add(itemWidget);
continue;
}
// Certain items are always lost on death and have a white outline which we need to add
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(i.getId());
if (alwaysLostItem != null)
{
// Some of these items are kept on death (outside wildy), like the Rune pouch. Ignore them
if (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0)
{
final Widget itemWidget = createItemWidget(lost, itemQuantity, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 0, itemQuantity, c.getName());
itemWidget.setBorderType(2); // white outline
lostItems.add(itemWidget);
hasAlwaysLost = true;
continue;
}
// the rune pouch is "always lost" but its kept outside of pvp, and does not count towards your keep count
}
else if (keepCount > 0)
{
// Keep most valuable items regardless of trade-ability.
if (i.getQuantity() > keepCount)
{
final Widget itemWidget = createItemWidget(kept, keepCount, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, keepCount, c.getName());
keptItems.add(itemWidget);
itemQuantity -= keepCount;
keepCount = 0;
// Fall through to below to drop the rest of the stack
}
else
{
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
keptItems.add(itemWidget);
keepCount -= i.getQuantity();
continue;
}
}
// Items are kept if:
// 1) is not tradeable
// 2) is under the deep wilderness line
// 3) is outside of the wilderness, or item has a broken form
if (!Pets.isPet(id)
&& !isTradeable(c) && wildyLevel <= DEEP_WILDY
&& (wildyLevel <= 0 || BrokenOnDeathItem.isBrokenOnDeath(i.getId())))
{
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
keptItems.add(itemWidget);
}
else
{
// Otherwise, the item is lost
final Widget itemWidget = createItemWidget(lost, itemQuantity, c);
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 0, itemQuantity, c.getName());
lostItems.add(itemWidget);
}
}
int rows = (keptItems.size() + MAX_ROW_ITEMS - 1) / MAX_ROW_ITEMS; int rows = (keptItems.size() + MAX_ROW_ITEMS - 1) / MAX_ROW_ITEMS;
// Show an empty row if there isn't anything // Show an empty row if there isn't anything
@@ -330,36 +263,209 @@ public class ItemsKeptOnDeathPlugin extends Plugin
positionWidgetItems(kept, keptItems); positionWidgetItems(kept, keptItems);
positionWidgetItems(lost, lostItems); positionWidgetItems(lost, lostItems);
updateKeptWidgetInfoText(hasAlwaysLost, keptItems, lostItems); updateKeptWidgetInfoText(deathItems.isHasAlwaysLost(), keptItems, lostItems);
}
/**
* Calculates which items will be kept/lost. first list is kept items, second is lost.
*
* @param inv players inventory
* @param equip players equipement
* @return list of items kept followed by a list of items lost
*/
@VisibleForTesting
DeathItems calculateKeptLostItems(final Item[] inv, final Item[] equip)
{
final List<Item> items = new ArrayList<>();
Collections.addAll(items, inv);
Collections.addAll(items, equip);
// Sort by item price
items.sort(Comparator.comparing(this::getDeathPrice).reversed());
boolean hasClueBox = false;
boolean hasAlwaysLost = false;
int keepCount = getDefaultItemsKept();
final List<ItemStack> keptItems = new ArrayList<>();
final List<ItemStack> lostItems = new ArrayList<>();
for (final Item i : items)
{
final int id = i.getId();
int qty = i.getQuantity();
if (id == -1)
{
continue;
}
final ItemDefinition c = itemManager.getItemDefinition(i.getId());
// Bonds are always kept and do not count towards the limit.
if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE)
{
keptItems.add(new ItemStack(id, qty));
continue;
}
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(id);
if (alwaysLostItem != null && (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0))
{
hasAlwaysLost = true;
hasClueBox = hasClueBox || id == ItemID.CLUE_BOX;
lostItems.add(new ItemStack(id, qty));
continue;
}
if (keepCount > 0)
{
// Keep most valuable items regardless of trade-ability.
if (i.getQuantity() > keepCount)
{
keptItems.add(new ItemStack(id, keepCount));
qty -= keepCount;
keepCount = 0;
// Fall through to determine if the rest of the stack should drop
}
else
{
keptItems.add(new ItemStack(id, qty));
keepCount -= qty;
continue;
}
}
// Items are kept if:
// 1) is not tradeable
// 2) is under the deep wilderness line
// 3) is outside of the wilderness, or item has a broken form
if (!Pets.isPet(id)
&& !LostIfNotProtected.isLostIfNotProtected(id)
&& !isTradeable(itemManager.getItemDefinition(id)) && wildyLevel <= DEEP_WILDY
&& (wildyLevel <= 0 || BrokenOnDeathItem.isBrokenOnDeath(i.getId())))
{
keptItems.add(new ItemStack(id, qty));
}
else
{
// Otherwise, the item is lost
lostItems.add(new ItemStack(id, qty));
}
}
if (hasClueBox)
{
boolean alreadyProtectingClue = false;
for (final ItemStack item : keptItems)
{
if (isClueBoxable(item.getId()))
{
alreadyProtectingClue = true;
break;
}
}
if (!alreadyProtectingClue)
{
int clueId = -1;
// Clue box protects the last clue in your inventory so loop over the players inv
for (final Item i : inv)
{
final int id = i.getId();
if (id != -1 && isClueBoxable(id))
{
clueId = id;
}
}
if (clueId != -1)
{
// Move the boxed item to the kept items container and remove it from the lost items container
for (final ItemStack boxableItem : lostItems)
{
if (boxableItem.getId() == clueId)
{
if (boxableItem.getQty() > 1)
{
boxableItem.setQty(boxableItem.getQty() - 1);
keptItems.add(new ItemStack(clueId, 1));
}
else
{
lostItems.remove(boxableItem);
keptItems.add(boxableItem);
}
break;
}
}
}
}
}
return new DeathItems(keptItems, lostItems, hasAlwaysLost);
}
@VisibleForTesting
boolean isClueBoxable(final int itemID)
{
final String name = itemManager.getItemDefinition(itemID).getName();
return name.contains("Clue scroll (") || name.contains("Reward casket (");
} }
/** /**
* Get the price of an item * Get the price of an item
*
* @param item * @param item
* @return * @return
*/ */
private int getDeathPrice(Item item) @VisibleForTesting
int getDeathPrice(Item item)
{ {
// 1) Check if the death price is dynamically calculated, if so return that value
// 2) If death price is based off another item default to that price, otherwise apply normal ItemMapping GE price
// 3) If still no price, default to store price
// 4) Apply fixed price offset if applicable
int itemId = item.getId(); int itemId = item.getId();
// Unnote/unplaceholder item // Unnote/unplaceholder item
int canonicalizedItemId = itemManager.canonicalize(itemId); int canonicalizedItemId = itemManager.canonicalize(itemId);
int exchangePrice = itemManager.getItemPrice(canonicalizedItemId); int exchangePrice = 0;
final DynamicPriceItem dynamicPrice = DynamicPriceItem.find(canonicalizedItemId);
if (dynamicPrice != null)
{
final ItemDefinition c1 = itemManager.getItemDefinition(canonicalizedItemId);
exchangePrice = c1.getPrice();
final int basePrice = itemManager.getItemPrice(dynamicPrice.getChargedId(), true);
return dynamicPrice.calculateDeathPrice(basePrice);
}
// Some items have artificially offset death prices - such as ring imbues
// which are +2k over the non imbues. Check if the item has a fixed price offset
final FixedPriceItem fixedPrice = FixedPriceItem.find(canonicalizedItemId);
if (fixedPrice != null && fixedPrice.getBaseId() != -1)
{
// Grab base item price
exchangePrice = itemManager.getItemPrice(fixedPrice.getBaseId(), true);
}
else
{
// Account for items whose death value comes from their tradeable variant (barrows) or components (ornate kits)
for (final int mappedID : ItemMapping.map(canonicalizedItemId))
{
exchangePrice += itemManager.getItemPrice(mappedID, true);
}
}
if (exchangePrice == 0) if (exchangePrice == 0)
{ {
final ItemDefinition c1 = itemManager.getItemDefinition(canonicalizedItemId); final ItemDefinition c1 = itemManager.getItemDefinition(canonicalizedItemId);
exchangePrice = c1.getPrice(); exchangePrice = c1.getPrice();
} }
else
{ // Apply fixed price offset
// Some items have artifically applied death prices - such as ring imbues exchangePrice += fixedPrice == null ? 0 : fixedPrice.getOffset();
// which are +2k over the non imbues. Check if the item has a fixed price.
FixedPriceItem fixedPrice = FixedPriceItem.find(canonicalizedItemId);
if (fixedPrice != null)
{
// Apply fixed price offset
exchangePrice += fixedPrice.getOffset();
}
}
return exchangePrice; return exchangePrice;
} }
@@ -591,21 +697,29 @@ public class ItemsKeptOnDeathPlugin extends Plugin
/** /**
* Creates an Item Widget for use inside the Kept on Death Interface * Creates an Item Widget for use inside the Kept on Death Interface
* *
* @param qty Amount of item * @param parent Widget to add element too as a child
* @param c Items Composition * @param item the TempItem representing the item
* @return * @param kept is the item being shown in the kept items container
* @return the Widget that was added to the `parent`
*/ */
private static Widget createItemWidget(final Widget parent, final int qty, final ItemDefinition c) private Widget createItemWidget(final Widget parent, final ItemStack item, boolean kept)
{ {
final int id = item.getId();
final int qty = item.getQty();
final ItemDefinition c = itemManager.getItemDefinition(id);
final Widget itemWidget = parent.createChild(-1, WidgetType.GRAPHIC); final Widget itemWidget = parent.createChild(-1, WidgetType.GRAPHIC);
itemWidget.setItemId(c.getId());
itemWidget.setItemQuantity(qty);
itemWidget.setHasListener(true);
itemWidget.setOriginalWidth(Constants.ITEM_SPRITE_WIDTH); itemWidget.setOriginalWidth(Constants.ITEM_SPRITE_WIDTH);
itemWidget.setOriginalHeight(Constants.ITEM_SPRITE_HEIGHT); itemWidget.setOriginalHeight(Constants.ITEM_SPRITE_HEIGHT);
itemWidget.setBorderType(1); itemWidget.setItemId(id);
itemWidget.setItemQuantity(qty);
itemWidget.setAction(1, String.format("Item: <col=ff981f>%s", c.getName())); itemWidget.setAction(1, String.format("Item: <col=ff981f>%s", c.getName()));
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, kept ? 1 : 0, qty, c.getName());
itemWidget.setHasListener(true);
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(id);
final boolean whiteBorder = alwaysLostItem != null && (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0);
itemWidget.setBorderType(whiteBorder ? 2 : 1);
return itemWidget; return itemWidget;
} }

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.itemskeptondeath;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import net.runelite.api.ItemID;
final class LostIfNotProtected
{
private static final Set<Integer> ITEMS = ImmutableSet.of(
ItemID.AMULET_OF_THE_DAMNED,
ItemID.RING_OF_CHAROS, ItemID.RING_OF_CHAROSA,
ItemID.LUNAR_STAFF,
ItemID.SHADOW_SWORD,
ItemID.KERIS, ItemID.KERISP, ItemID.KERISP_10583, ItemID.KERISP_10584
);
public static boolean isLostIfNotProtected(int id)
{
return ITEMS.contains(id);
}
}

View File

@@ -103,10 +103,153 @@ public interface KeyRemappingConfig extends Config
position = 6, position = 6,
keyName = "fkeyRemap", keyName = "fkeyRemap",
name = "Remap F Keys", name = "Remap F Keys",
description = "Configures whether F-Keys are Remapped to 1 (F1) through 0 (F10), '-' (F11), and '=' (F12)" description = "Configures whether F-Keys use remapped keys"
) )
default boolean fkeyRemap() default boolean fkeyRemap()
{ {
return false; return false;
} }
@ConfigItem(
position = 7,
keyName = "f1",
name = "F1",
description = "The key which will replace {F1}."
)
default ModifierlessKeybind f1()
{
return new ModifierlessKeybind(KeyEvent.VK_1, 0);
}
@ConfigItem(
position = 8,
keyName = "f2",
name = "F2",
description = "The key which will replace {F2}."
)
default ModifierlessKeybind f2()
{
return new ModifierlessKeybind(KeyEvent.VK_2, 0);
}
@ConfigItem(
position = 9,
keyName = "f3",
name = "F3",
description = "The key which will replace {F3}."
)
default ModifierlessKeybind f3()
{
return new ModifierlessKeybind(KeyEvent.VK_3, 0);
}
@ConfigItem(
position = 10,
keyName = "f4",
name = "F4",
description = "The key which will replace {F4}."
)
default ModifierlessKeybind f4()
{
return new ModifierlessKeybind(KeyEvent.VK_4, 0);
}
@ConfigItem(
position = 11,
keyName = "f5",
name = "F5",
description = "The key which will replace {F5}."
)
default ModifierlessKeybind f5()
{
return new ModifierlessKeybind(KeyEvent.VK_5, 0);
}
@ConfigItem(
position = 12,
keyName = "f6",
name = "F6",
description = "The key which will replace {F6}."
)
default ModifierlessKeybind f6()
{
return new ModifierlessKeybind(KeyEvent.VK_6, 0);
}
@ConfigItem(
position = 13,
keyName = "f7",
name = "F7",
description = "The key which will replace {F7}."
)
default ModifierlessKeybind f7()
{
return new ModifierlessKeybind(KeyEvent.VK_7, 0);
}
@ConfigItem(
position = 14,
keyName = "f8",
name = "F8",
description = "The key which will replace {F8}."
)
default ModifierlessKeybind f8()
{
return new ModifierlessKeybind(KeyEvent.VK_8, 0);
}
@ConfigItem(
position = 15,
keyName = "f9",
name = "F9",
description = "The key which will replace {F9}."
)
default ModifierlessKeybind f9()
{
return new ModifierlessKeybind(KeyEvent.VK_9, 0);
}
@ConfigItem(
position = 16,
keyName = "f10",
name = "F10",
description = "The key which will replace {F10}."
)
default ModifierlessKeybind f10()
{
return new ModifierlessKeybind(KeyEvent.VK_0, 0);
}
@ConfigItem(
position = 17,
keyName = "f11",
name = "F11",
description = "The key which will replace {F11}."
)
default ModifierlessKeybind f11()
{
return new ModifierlessKeybind(KeyEvent.VK_MINUS, 0);
}
@ConfigItem(
position = 18,
keyName = "f12",
name = "F12",
description = "The key which will replace {F12}."
)
default ModifierlessKeybind f12()
{
return new ModifierlessKeybind(KeyEvent.VK_EQUALS, 0);
}
@ConfigItem(
position = 19,
keyName = "esc",
name = "ESC",
description = "The key which will replace {ESC}."
)
default ModifierlessKeybind esc()
{
return new ModifierlessKeybind(KeyEvent.VK_ESCAPE, 0);
}
} }

View File

@@ -35,30 +35,19 @@ import net.runelite.api.Client;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.VarClientStr; import net.runelite.api.VarClientStr;
import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.Keybind;
import net.runelite.client.config.ModifierlessKeybind;
import net.runelite.client.input.KeyListener; import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseAdapter; import net.runelite.client.input.MouseAdapter;
@Singleton @Singleton
class KeyRemappingListener extends MouseAdapter implements KeyListener class KeyRemappingListener extends MouseAdapter implements KeyListener
{ {
private static final Keybind ONE = new ModifierlessKeybind(KeyEvent.VK_1, 0);
private static final Keybind TWO = new ModifierlessKeybind(KeyEvent.VK_2, 0);
private static final Keybind THREE = new ModifierlessKeybind(KeyEvent.VK_3, 0);
private static final Keybind FOUR = new ModifierlessKeybind(KeyEvent.VK_4, 0);
private static final Keybind FIVE = new ModifierlessKeybind(KeyEvent.VK_5, 0);
private static final Keybind SIX = new ModifierlessKeybind(KeyEvent.VK_6, 0);
private static final Keybind SEVEN = new ModifierlessKeybind(KeyEvent.VK_7, 0);
private static final Keybind EIGHT = new ModifierlessKeybind(KeyEvent.VK_8, 0);
private static final Keybind NINE = new ModifierlessKeybind(KeyEvent.VK_9, 0);
private static final Keybind ZERO = new ModifierlessKeybind(KeyEvent.VK_0, 0);
private static final Keybind MINUS = new ModifierlessKeybind(KeyEvent.VK_MINUS, 0);
private static final Keybind EQUALS = new ModifierlessKeybind(KeyEvent.VK_EQUALS, 0);
@Inject @Inject
private KeyRemappingPlugin plugin; private KeyRemappingPlugin plugin;
@Inject
private KeyRemappingConfig config;
@Inject @Inject
private Client client; private Client client;
@@ -111,66 +100,71 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
// to select options // to select options
if (plugin.isFkeyRemap() && !plugin.isDialogOpen()) if (plugin.isFkeyRemap() && !plugin.isDialogOpen())
{ {
if (ONE.matches(e)) if (config.f1().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F1); modified.put(e.getKeyCode(), KeyEvent.VK_F1);
e.setKeyCode(KeyEvent.VK_F1); e.setKeyCode(KeyEvent.VK_F1);
} }
else if (TWO.matches(e)) else if (config.f2().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F2); modified.put(e.getKeyCode(), KeyEvent.VK_F2);
e.setKeyCode(KeyEvent.VK_F2); e.setKeyCode(KeyEvent.VK_F2);
} }
else if (THREE.matches(e)) else if (config.f3().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F3); modified.put(e.getKeyCode(), KeyEvent.VK_F3);
e.setKeyCode(KeyEvent.VK_F3); e.setKeyCode(KeyEvent.VK_F3);
} }
else if (FOUR.matches(e)) else if (config.f4().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F4); modified.put(e.getKeyCode(), KeyEvent.VK_F4);
e.setKeyCode(KeyEvent.VK_F4); e.setKeyCode(KeyEvent.VK_F4);
} }
else if (FIVE.matches(e)) else if (config.f5().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F5); modified.put(e.getKeyCode(), KeyEvent.VK_F5);
e.setKeyCode(KeyEvent.VK_F5); e.setKeyCode(KeyEvent.VK_F5);
} }
else if (SIX.matches(e)) else if (config.f6().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F6); modified.put(e.getKeyCode(), KeyEvent.VK_F6);
e.setKeyCode(KeyEvent.VK_F6); e.setKeyCode(KeyEvent.VK_F6);
} }
else if (SEVEN.matches(e)) else if (config.f7().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F7); modified.put(e.getKeyCode(), KeyEvent.VK_F7);
e.setKeyCode(KeyEvent.VK_F7); e.setKeyCode(KeyEvent.VK_F7);
} }
else if (EIGHT.matches(e)) else if (config.f8().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F8); modified.put(e.getKeyCode(), KeyEvent.VK_F8);
e.setKeyCode(KeyEvent.VK_F8); e.setKeyCode(KeyEvent.VK_F8);
} }
else if (NINE.matches(e)) else if (config.f9().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F9); modified.put(e.getKeyCode(), KeyEvent.VK_F9);
e.setKeyCode(KeyEvent.VK_F9); e.setKeyCode(KeyEvent.VK_F9);
} }
else if (ZERO.matches(e)) else if (config.f10().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F10); modified.put(e.getKeyCode(), KeyEvent.VK_F10);
e.setKeyCode(KeyEvent.VK_F10); e.setKeyCode(KeyEvent.VK_F10);
} }
else if (MINUS.matches(e)) else if (config.f11().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F11); modified.put(e.getKeyCode(), KeyEvent.VK_F11);
e.setKeyCode(KeyEvent.VK_F11); e.setKeyCode(KeyEvent.VK_F11);
} }
else if (EQUALS.matches(e)) else if (config.f12().matches(e))
{ {
modified.put(e.getKeyCode(), KeyEvent.VK_F12); modified.put(e.getKeyCode(), KeyEvent.VK_F12);
e.setKeyCode(KeyEvent.VK_F12); e.setKeyCode(KeyEvent.VK_F12);
} }
else if (config.esc().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_ESCAPE);
e.setKeyCode(KeyEvent.VK_ESCAPE);
}
} }
switch (e.getKeyCode()) switch (e.getKeyCode())
@@ -189,8 +183,12 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
{ {
switch (e.getKeyCode()) switch (e.getKeyCode())
{ {
case KeyEvent.VK_ENTER:
case KeyEvent.VK_ESCAPE: case KeyEvent.VK_ESCAPE:
// When existing typing mode, block the escape key
// so that it doesn't trigger the in-game hotkeys
e.consume();
// FALLTHROUGH
case KeyEvent.VK_ENTER:
plugin.setTyping(false); plugin.setTyping(false);
clientThread.invoke(plugin::lockChat); clientThread.invoke(plugin::lockChat);
break; break;
@@ -240,54 +238,58 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
if (plugin.isFkeyRemap()) if (plugin.isFkeyRemap())
{ {
if (ONE.matches(e)) if (config.f1().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F1); e.setKeyCode(KeyEvent.VK_F1);
} }
else if (TWO.matches(e)) else if (config.f2().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F2); e.setKeyCode(KeyEvent.VK_F2);
} }
else if (THREE.matches(e)) else if (config.f3().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F3); e.setKeyCode(KeyEvent.VK_F3);
} }
else if (FOUR.matches(e)) else if (config.f4().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F4); e.setKeyCode(KeyEvent.VK_F4);
} }
else if (FIVE.matches(e)) else if (config.f5().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F5); e.setKeyCode(KeyEvent.VK_F5);
} }
else if (SIX.matches(e)) else if (config.f6().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F6); e.setKeyCode(KeyEvent.VK_F6);
} }
else if (SEVEN.matches(e)) else if (config.f7().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F7); e.setKeyCode(KeyEvent.VK_F7);
} }
else if (EIGHT.matches(e)) else if (config.f8().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F8); e.setKeyCode(KeyEvent.VK_F8);
} }
else if (NINE.matches(e)) else if (config.f9().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F9); e.setKeyCode(KeyEvent.VK_F9);
} }
else if (ZERO.matches(e)) else if (config.f10().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F10); e.setKeyCode(KeyEvent.VK_F10);
} }
else if (MINUS.matches(e)) else if (config.f11().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F11); e.setKeyCode(KeyEvent.VK_F11);
} }
else if (EQUALS.matches(e)) else if (config.f12().matches(e))
{ {
e.setKeyCode(KeyEvent.VK_F12); e.setKeyCode(KeyEvent.VK_F12);
} }
else if (config.esc().matches(e))
{
e.setKeyCode(KeyEvent.VK_ESCAPE);
}
} }
} }
else else

View File

@@ -34,7 +34,6 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor; import net.runelite.api.Actor;
import static net.runelite.api.AnimationID.LIZARDMAN_SHAMAN_SPAWN; import static net.runelite.api.AnimationID.LIZARDMAN_SHAMAN_SPAWN;
import net.runelite.api.ChatMessageType;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
@@ -104,7 +103,8 @@ public class LizardmenShamanPlugin extends Plugin
@Subscribe @Subscribe
public void onChatMessage(ChatMessage event) public void onChatMessage(ChatMessage event)
{ {
if (this.notifyOnSpawn && event.getType() == ChatMessageType.GAMEMESSAGE && event.getMessage().contains(MESSAGE)) if (this.notifyOnSpawn && /* event.getType() == ChatMessageType.GAMEMESSAGE && */event.getMessage().contains(MESSAGE))
// ChatMessageType should probably be SPAM <- should be tested first though
{ {
notifier.notify(MESSAGE); notifier.notify(MESSAGE);
} }

View File

@@ -1,126 +0,0 @@
/*
* Copyright (c) 2018 Abex
* 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.regenmeter;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.VarPlayer;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@Singleton
public class RegenMeterOverlay extends Overlay
{
private static final Color HITPOINTS_COLOR = brighter(0x9B0703);
private static final Color SPECIAL_COLOR = brighter(0x1E95B0);
private static final Color OVERLAY_COLOR = new Color(255, 255, 255, 60);
private static final double DIAMETER = 26D;
private static final int OFFSET = 27;
private static final Stroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
private final Client client;
private final RegenMeterPlugin plugin;
private Rectangle getBounds(WidgetInfo widgetInfo)
{
Widget widget = client.getWidget(widgetInfo);
if (widget == null || widget.isHidden())
{
return null;
}
return widget.getBounds();
}
private static Color brighter(int color)
{
float[] hsv = new float[3];
Color.RGBtoHSB(color >>> 16, (color >> 8) & 0xFF, color & 0xFF, hsv);
return Color.getHSBColor(hsv[0], 1.f, 1.f);
}
@Inject
public RegenMeterOverlay(final Client client, final RegenMeterPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D g)
{
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
if (plugin.isShowHitpoints())
{
renderRegen(g, WidgetInfo.MINIMAP_HEALTH_ORB, plugin.getHitpointsPercentage(), HITPOINTS_COLOR);
}
if (plugin.isShowSpecial())
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_ENABLED) == 1)
{
final Rectangle bounds = getBounds(WidgetInfo.MINIMAP_SPEC_ORB);
if (bounds != null)
{
g.setColor(RegenMeterOverlay.OVERLAY_COLOR);
g.fillOval(
bounds.x + OFFSET,
bounds.y + (int) (bounds.height / 2D - (DIAMETER) / 2D),
(int) DIAMETER, (int) DIAMETER);
}
}
renderRegen(g, WidgetInfo.MINIMAP_SPEC_ORB, plugin.getSpecialPercentage(), SPECIAL_COLOR);
}
return null;
}
private void renderRegen(Graphics2D g, WidgetInfo widgetInfo, double percent, Color color)
{
final Rectangle bounds = getBounds(widgetInfo);
if (bounds != null)
{
Arc2D.Double arc = new Arc2D.Double(bounds.x + OFFSET, bounds.y + (bounds.height / 2 - DIAMETER / 2), DIAMETER, DIAMETER, 90.d, -360.d * percent, Arc2D.OPEN);
g.setStroke(STROKE);
g.setColor(color);
g.draw(arc);
}
}
}

View File

@@ -1,201 +0,0 @@
/*
* Copyright (c) 2019, Sean Dewar <https://github.com/seandewar>
* Copyright (c) 2018, Abex
* Copyright (c) 2018, Zimaya <https://github.com/Zimaya>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.regenmeter;
import com.google.inject.Provides;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.Prayer;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Regeneration Meter",
description = "Track and show the hitpoints and special attack regeneration timers",
tags = {"combat", "health", "hitpoints", "special", "attack", "overlay", "notifications"}
)
@Singleton
public class RegenMeterPlugin extends Plugin
{
private static final int SPEC_REGEN_TICKS = 50;
private static final int NORMAL_HP_REGEN_TICKS = 100;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private Notifier notifier;
@Inject
private RegenMeterOverlay overlay;
@Inject
private RegenMeterConfig config;
@Getter(AccessLevel.PACKAGE)
private double hitpointsPercentage;
@Getter(AccessLevel.PACKAGE)
private double specialPercentage;
private int ticksSinceSpecRegen;
private int ticksSinceHPRegen;
private boolean wasRapidHeal;
@Getter(AccessLevel.PACKAGE)
private boolean showHitpoints;
@Getter(AccessLevel.PACKAGE)
private boolean showSpecial;
private boolean showWhenNoChange;
private int getNotifyBeforeHpRegenSeconds;
@Provides
RegenMeterConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(RegenMeterConfig.class);
}
@Override
protected void startUp() throws Exception
{
updateConfig();
overlayManager.add(overlay);
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
}
@Subscribe
private void onGameStateChanged(GameStateChanged ev)
{
if (ev.getGameState() == GameState.HOPPING || ev.getGameState() == GameState.LOGIN_SCREEN)
{
ticksSinceHPRegen = -2; // For some reason this makes this accurate
ticksSinceSpecRegen = 0;
}
}
@Subscribe
private void onVarbitChanged(VarbitChanged ev)
{
boolean isRapidHeal = client.isPrayerActive(Prayer.RAPID_HEAL);
if (wasRapidHeal != isRapidHeal)
{
ticksSinceHPRegen = 0;
}
wasRapidHeal = isRapidHeal;
}
@Subscribe
public void onGameTick(GameTick event)
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) == 1000)
{
// The recharge doesn't tick when at 100%
ticksSinceSpecRegen = 0;
}
else
{
ticksSinceSpecRegen = (ticksSinceSpecRegen + 1) % SPEC_REGEN_TICKS;
}
specialPercentage = ticksSinceSpecRegen / (double) SPEC_REGEN_TICKS;
int ticksPerHPRegen = NORMAL_HP_REGEN_TICKS;
if (client.isPrayerActive(Prayer.RAPID_HEAL))
{
ticksPerHPRegen /= 2;
}
ticksSinceHPRegen = (ticksSinceHPRegen + 1) % ticksPerHPRegen;
hitpointsPercentage = ticksSinceHPRegen / (double) ticksPerHPRegen;
int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS);
int maxHP = client.getRealSkillLevel(Skill.HITPOINTS);
if (currentHP == maxHP && !this.showWhenNoChange)
{
hitpointsPercentage = 0;
}
else if (currentHP > maxHP)
{
// Show it going down
hitpointsPercentage = 1 - hitpointsPercentage;
}
if (this.getNotifyBeforeHpRegenSeconds > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
{
notifier.notify("[" + client.getLocalPlayer().getName() + "] regenerates their next hitpoint soon!");
}
}
private boolean shouldNotifyHpRegenThisTick(int ticksPerHPRegen)
{
// if the configured duration lies between two ticks, choose the earlier tick
final int ticksBeforeHPRegen = ticksPerHPRegen - ticksSinceHPRegen;
final int notifyTick = (int) Math.ceil(this.getNotifyBeforeHpRegenSeconds * 1000d / Constants.GAME_TICK_LENGTH);
return ticksBeforeHPRegen == notifyTick;
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("regenmeter"))
{
updateConfig();
}
}
private void updateConfig()
{
this.showHitpoints = config.showHitpoints();
this.showSpecial = config.showSpecial();
this.showWhenNoChange = config.showWhenNoChange();
this.getNotifyBeforeHpRegenSeconds = config.getNotifyBeforeHpRegenSeconds();
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.runenergy;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import org.apache.commons.lang3.StringUtils;
@Singleton
class RunEnergyOverlay extends Overlay
{
private final RunEnergyPlugin plugin;
private final Client client;
private final RunEnergyConfig config;
private final TooltipManager tooltipManager;
@Inject
private RunEnergyOverlay(final RunEnergyPlugin plugin, final Client client, final RunEnergyConfig config, final TooltipManager tooltipManager)
{
this.plugin = plugin;
this.client = client;
this.config = config;
this.tooltipManager = tooltipManager;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}
@Override
public Dimension render(Graphics2D graphics)
{
final Widget runOrb = client.getWidget(WidgetInfo.MINIMAP_TOGGLE_RUN_ORB);
if (runOrb == null || runOrb.isHidden())
{
return null;
}
final Rectangle bounds = runOrb.getBounds();
if (bounds.getX() <= 0)
{
return null;
}
final Point mousePosition = client.getMouseCanvasPosition();
if (bounds.contains(mousePosition.getX(), mousePosition.getY()))
{
StringBuilder sb = new StringBuilder();
sb.append("Weight: ").append(client.getWeight()).append(" kg</br>");
if (config.replaceOrbText())
{
sb.append("Run Energy: ").append(client.getEnergy()).append("%");
}
else
{
sb.append("Run Time Remaining: ").append(plugin.getEstimatedRunTimeRemaining(false));
}
int secondsUntil100 = plugin.getEstimatedRecoverTimeRemaining();
if (secondsUntil100 > 0)
{
final int minutes = (int) Math.floor(secondsUntil100 / 60.0);
final int seconds = (int) Math.floor(secondsUntil100 - (minutes * 60.0));
sb.append("</br>").append("100% Energy In: ").append(minutes).append(':').append(StringUtils.leftPad(Integer.toString(seconds), 2, "0"));
}
tooltipManager.add(new Tooltip(sb.toString()));
}
return null;
}
}

View File

@@ -1,340 +0,0 @@
/*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.runenergy;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provides;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import static net.runelite.api.ItemID.AGILITY_CAPE;
import static net.runelite.api.ItemID.AGILITY_CAPET;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_11861;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13589;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13590;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13601;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13602;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13613;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13614;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13625;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13626;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13637;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13638;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13677;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13678;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21076;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21078;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_11853;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13581;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13582;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13593;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13594;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13605;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13606;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13617;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13618;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13629;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13630;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13669;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13670;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21064;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21066;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_11859;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13587;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13588;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13599;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13600;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13611;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13612;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13623;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13624;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13635;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13636;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13675;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13676;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21073;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21075;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_11851;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13579;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13580;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13591;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13592;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13603;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13604;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13615;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13616;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13627;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13628;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13667;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13668;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21061;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21063;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_11857;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13585;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13586;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13597;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13598;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13609;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13610;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13621;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13622;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13633;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13634;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13673;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13674;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21070;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21072;
import static net.runelite.api.ItemID.GRACEFUL_TOP_11855;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13583;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13584;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13595;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13596;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13607;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13608;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13619;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13620;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13631;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13632;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13671;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13672;
import static net.runelite.api.ItemID.GRACEFUL_TOP_21067;
import static net.runelite.api.ItemID.GRACEFUL_TOP_21069;
import static net.runelite.api.ItemID.MAX_CAPE;
import net.runelite.api.Skill;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import org.apache.commons.lang3.StringUtils;
@PluginDescriptor(
name = "Run Energy",
description = "Show various information related to run energy",
tags = {"overlay", "stamina"}
)
@Singleton
public class RunEnergyPlugin extends Plugin
{
// TODO It would be nice if we have the IDs for just the equipped variants of the Graceful set items.
private static final ImmutableSet<Integer> ALL_GRACEFUL_HOODS = ImmutableSet.of(
GRACEFUL_HOOD_11851, GRACEFUL_HOOD_13579, GRACEFUL_HOOD_13580, GRACEFUL_HOOD_13591, GRACEFUL_HOOD_13592,
GRACEFUL_HOOD_13603, GRACEFUL_HOOD_13604, GRACEFUL_HOOD_13615, GRACEFUL_HOOD_13616, GRACEFUL_HOOD_13627,
GRACEFUL_HOOD_13628, GRACEFUL_HOOD_13667, GRACEFUL_HOOD_13668, GRACEFUL_HOOD_21061, GRACEFUL_HOOD_21063
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_TOPS = ImmutableSet.of(
GRACEFUL_TOP_11855, GRACEFUL_TOP_13583, GRACEFUL_TOP_13584, GRACEFUL_TOP_13595, GRACEFUL_TOP_13596,
GRACEFUL_TOP_13607, GRACEFUL_TOP_13608, GRACEFUL_TOP_13619, GRACEFUL_TOP_13620, GRACEFUL_TOP_13631,
GRACEFUL_TOP_13632, GRACEFUL_TOP_13671, GRACEFUL_TOP_13672, GRACEFUL_TOP_21067, GRACEFUL_TOP_21069
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_LEGS = ImmutableSet.of(
GRACEFUL_LEGS_11857, GRACEFUL_LEGS_13585, GRACEFUL_LEGS_13586, GRACEFUL_LEGS_13597, GRACEFUL_LEGS_13598,
GRACEFUL_LEGS_13609, GRACEFUL_LEGS_13610, GRACEFUL_LEGS_13621, GRACEFUL_LEGS_13622, GRACEFUL_LEGS_13633,
GRACEFUL_LEGS_13634, GRACEFUL_LEGS_13673, GRACEFUL_LEGS_13674, GRACEFUL_LEGS_21070, GRACEFUL_LEGS_21072
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_GLOVES = ImmutableSet.of(
GRACEFUL_GLOVES_11859, GRACEFUL_GLOVES_13587, GRACEFUL_GLOVES_13588, GRACEFUL_GLOVES_13599, GRACEFUL_GLOVES_13600,
GRACEFUL_GLOVES_13611, GRACEFUL_GLOVES_13612, GRACEFUL_GLOVES_13623, GRACEFUL_GLOVES_13624, GRACEFUL_GLOVES_13635,
GRACEFUL_GLOVES_13636, GRACEFUL_GLOVES_13675, GRACEFUL_GLOVES_13676, GRACEFUL_GLOVES_21073, GRACEFUL_GLOVES_21075
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_BOOTS = ImmutableSet.of(
GRACEFUL_BOOTS_11861, GRACEFUL_BOOTS_13589, GRACEFUL_BOOTS_13590, GRACEFUL_BOOTS_13601, GRACEFUL_BOOTS_13602,
GRACEFUL_BOOTS_13613, GRACEFUL_BOOTS_13614, GRACEFUL_BOOTS_13625, GRACEFUL_BOOTS_13626, GRACEFUL_BOOTS_13637,
GRACEFUL_BOOTS_13638, GRACEFUL_BOOTS_13677, GRACEFUL_BOOTS_13678, GRACEFUL_BOOTS_21076, GRACEFUL_BOOTS_21078
);
// Agility skill capes and the non-cosmetic Max capes also count for the Graceful set effect
private static final ImmutableSet<Integer> ALL_GRACEFUL_CAPES = ImmutableSet.of(
GRACEFUL_CAPE_11853, GRACEFUL_CAPE_13581, GRACEFUL_CAPE_13582, GRACEFUL_CAPE_13593, GRACEFUL_CAPE_13594,
GRACEFUL_CAPE_13605, GRACEFUL_CAPE_13606, GRACEFUL_CAPE_13617, GRACEFUL_CAPE_13618, GRACEFUL_CAPE_13629,
GRACEFUL_CAPE_13630, GRACEFUL_CAPE_13669, GRACEFUL_CAPE_13670, GRACEFUL_CAPE_21064, GRACEFUL_CAPE_21066,
AGILITY_CAPE, AGILITY_CAPET, MAX_CAPE
);
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private RunEnergyOverlay energyOverlay;
@Inject
private RunEnergyConfig energyConfig;
private boolean localPlayerRunningToDestination;
private WorldPoint prevLocalPlayerLocation;
@Provides
RunEnergyConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(RunEnergyConfig.class);
}
@Override
protected void startUp() throws Exception
{
overlayManager.add(energyOverlay);
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(energyOverlay);
localPlayerRunningToDestination = false;
prevLocalPlayerLocation = null;
resetRunOrbText();
}
@Subscribe
public void onGameTick(GameTick event)
{
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
prevLocalPlayerLocation = client.getLocalPlayer().getWorldLocation();
if (energyConfig.replaceOrbText())
{
setRunOrbText(getEstimatedRunTimeRemaining(true));
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("runenergy") && !energyConfig.replaceOrbText())
{
resetRunOrbText();
}
}
private void setRunOrbText(String text)
{
Widget runOrbText = client.getWidget(WidgetInfo.MINIMAP_RUN_ORB_TEXT);
if (runOrbText != null)
{
runOrbText.setText(text);
}
}
private void resetRunOrbText()
{
setRunOrbText(Integer.toString(client.getEnergy()));
}
String getEstimatedRunTimeRemaining(boolean inSeconds)
{
// Calculate the amount of energy lost every tick.
// Negative weight has the same depletion effect as 0 kg.
final int effectiveWeight = Math.max(client.getWeight(), 0);
double lossRate = (Math.min(effectiveWeight, 64) / 100.0) + 0.64;
if (client.getVar(Varbits.RUN_SLOWED_DEPLETION_ACTIVE) != 0)
{
lossRate *= 0.3; // Stamina effect reduces energy depletion to 30%
}
// Calculate the number of seconds left
final double secondsLeft = (client.getEnergy() * Constants.GAME_TICK_LENGTH) / (lossRate * 1000.0);
// Return the text
if (inSeconds)
{
return (int) Math.floor(secondsLeft) + "s";
}
else
{
final int minutes = (int) Math.floor(secondsLeft / 60.0);
final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0));
return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0");
}
}
private boolean isLocalPlayerWearingFullGraceful()
{
final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
if (equipment == null)
{
return false;
}
final Item[] items = equipment.getItems();
// Check that the local player is wearing enough items to be using full Graceful
// (the Graceful boots will have the highest slot index in the worn set).
if (items == null || items.length <= EquipmentInventorySlot.BOOTS.getSlotIdx())
{
return false;
}
return (ALL_GRACEFUL_HOODS.contains(items[EquipmentInventorySlot.HEAD.getSlotIdx()].getId()) &&
ALL_GRACEFUL_TOPS.contains(items[EquipmentInventorySlot.BODY.getSlotIdx()].getId()) &&
ALL_GRACEFUL_LEGS.contains(items[EquipmentInventorySlot.LEGS.getSlotIdx()].getId()) &&
ALL_GRACEFUL_GLOVES.contains(items[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId()) &&
ALL_GRACEFUL_BOOTS.contains(items[EquipmentInventorySlot.BOOTS.getSlotIdx()].getId()) &&
ALL_GRACEFUL_CAPES.contains(items[EquipmentInventorySlot.CAPE.getSlotIdx()].getId()));
}
int getEstimatedRecoverTimeRemaining()
{
if (localPlayerRunningToDestination)
{
return -1;
}
// Calculate the amount of energy recovered every second
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360.0;
if (isLocalPlayerWearingFullGraceful())
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
// Calculate the number of seconds left
return (int) ((100 - client.getEnergy()) / recoverRate);
}
}

View File

@@ -1,675 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.SecondaryItem;
import net.runelite.client.plugins.skillcalculator.banked.ui.CriticalItemPanel;
import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@Slf4j
@Singleton
public class BankedCalculator extends JPanel
{
private static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#");
private final SkillCalculatorPanel parent;
private final Client client;
private final UICalculatorInputArea uiInput;
private final SkillCalculatorConfig config;
private final ItemManager itemManager;
private final CacheSkillData skillData = new CacheSkillData();
private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>();
// UI Input data
private float xpFactor = 1.0f;
private CalculatorType currentCalc;
private Skill currentSkill;
private double totalBankedXp = 0.0f;
private final JLabel totalLabel = new JLabel();
private final JPanel detailConfigContainer;
private final JPanel detailContainer;
// Banked Experience magic
private Map<Integer, Integer> bankMap = new HashMap<>();
private final Map<String, Boolean> categoryMap = new HashMap<>(); // Check if CriticalItem Category is enabled
private final Map<CriticalItem, CriticalItemPanel> panelMap = new HashMap<>();
private final Map<CriticalItem, Integer> criticalMap = new HashMap<>(); // Quantity of CriticalItem inside bankMap
private final Map<CriticalItem, Activity> activityMap = new HashMap<>(); // Selected Activity used for calculating xp
private final Map<CriticalItem, Integer> linkedMap = new HashMap<>(); // ItemID of item that links to the CriticalItem
BankedCalculator(
final SkillCalculatorPanel parent,
final Client client,
final UICalculatorInputArea uiInput,
final SkillCalculatorConfig config,
final ItemManager itemManager)
{
this.parent = parent;
this.client = client;
this.uiInput = uiInput;
this.config = config;
this.itemManager = itemManager;
setLayout(new DynamicGridLayout(0, 1, 0, 5));
detailContainer = new JPanel();
detailContainer.setLayout(new BoxLayout(detailContainer, BoxLayout.Y_AXIS));
detailConfigContainer = new JPanel();
detailConfigContainer.setLayout(new BoxLayout(detailConfigContainer, BoxLayout.Y_AXIS));
}
private void reset()
{
criticalMap.clear();
linkedMap.clear();
xpFactor = 1f;
}
/**
* Update target Xp and Level inputs to match current Xp + total banked XP
*/
private void syncInputFields()
{
// Update Target XP & Level to include total banked xp
int newTotal = (int) (uiInput.getCurrentXPInput() + totalBankedXp);
uiInput.setTargetXPInput(newTotal);
uiInput.setTargetLevelInput(Experience.getLevelForXp(newTotal));
}
/*
* Banked Experience Logic
*/
/**
* Shows the Banked Xp tab for the CalculatorType
*
* @param calculatorType Selected Calculator Type
*/
void openBanked(CalculatorType calculatorType)
{
// clean slate for creating the required panel
removeAll();
reset();
if (calculatorType.getSkill() != currentSkill)
{
// Only clear Category and Activity map on skill change.
activityMap.clear();
categoryMap.clear();
}
currentCalc = calculatorType;
currentSkill = calculatorType.getSkill();
bankMap = parent.getBankMap();
uiInput.setCurrentLevelInput(client.getRealSkillLevel(currentSkill));
uiInput.setCurrentXPInput(client.getSkillExperience(currentSkill));
// Only adds Banked Experience portion if enabled for this SkillCalc and have seen their bank
if (!calculatorType.isBankedXpFlag())
{
add(new JLabel("<html><div style='text-align: center;'>Banked Experience is not enabled for this skill.</div></html>", JLabel.CENTER));
}
else if (bankMap.size() <= 0)
{
add(new JLabel("Please visit a bank!", JLabel.CENTER));
}
else
{
// Prevent editing of the target level/exp since we automagically adjust them
uiInput.getUiFieldTargetLevel().setEditable(false);
uiInput.getUiFieldTargetXP().setEditable(false);
// Now we can actually show the Banked Experience Panel
// Adds Config Options for this panel
renderBankedXpOptions();
renderBonusXpOptions();
// sprite 202
calculatedBankedMaps();
// Calculate total banked experience and create detail container
refreshDetailContainer();
// Add back all necessary content
add(detailConfigContainer);
add(totalLabel);
add(detailContainer);
}
revalidate();
repaint();
// Update the input fields.
syncInputFields();
}
/**
* Add the config options for toggling each Item Category
*/
private void renderBankedXpOptions()
{
Set<String> categories = CriticalItem.getSkillCategories(currentSkill);
if (categories == null)
{
return;
}
add(new JLabel("Configs:"));
for (String category : categories)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(category);
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// Everything is enabled by default
uiCheckbox.setSelected(true);
categoryMap.put(category, true);
// Adjust Total Banked XP check-state of the box.
uiCheckbox.addActionListener(e -> toggleCategory(category, uiCheckbox.isSelected()));
uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(uiCheckbox, BorderLayout.EAST);
add(uiOption);
add(Box.createRigidArea(new Dimension(0, 5)));
}
}
/**
* Used to toggle Categories of Items inside the Banked Xp tab
*
* @param category Category Name
* @param enabled is enabled
*/
private void toggleCategory(String category, boolean enabled)
{
categoryMap.put(category, enabled);
refreshDetailContainer();
}
/**
* Creates the Maps used for easy access when calculating Banked Xp
*/
private void calculatedBankedMaps()
{
// Grab all CriticalItems for this skill
List<CriticalItem> items = CriticalItem.getBySkillName(currentSkill);
// Loop over all Critical Items for this skill and determine how many are in the bank
for (CriticalItem item : items)
{
Integer qty = bankMap.get(item.getItemID());
if (qty != null && qty > 0)
{
if (criticalMap.containsKey(item))
{
criticalMap.put(item, criticalMap.get(item) + qty);
}
else
{
criticalMap.put(item, qty);
}
// Ensure the item this is linked to maps back to us.
if (item.getLinkedItemId() != -1)
{
CriticalItem i = CriticalItem.getByItemId(item.getLinkedItemId());
if (i != null)
{
linkedMap.put(i, item.getItemID());
}
}
}
}
}
/**
* Populates the detailContainer with the necessary CriticalItemPanels
*/
private void refreshDetailContainer()
{
detailContainer.removeAll();
panelMap.clear();
Map<CriticalItem, Integer> map = getBankedXpBreakdown();
for (Map.Entry<CriticalItem, Integer> entry : map.entrySet())
{
CriticalItem item = entry.getKey();
createItemPanel(item);
}
detailContainer.revalidate();
detailContainer.repaint();
calculateBankedXpTotal();
}
/**
* Creates an Individual Item Panel if it should be displayed
*
* @param item CriticalItem this information is tied too
*/
private void createItemPanel(CriticalItem item)
{
// Category Included?
if (categoryMap.get(item.getCategory()))
{
// Get possible activities limited to current level
List<Activity> activities = Activity.getByCriticalItem(item, uiInput.getCurrentLevelInput());
// Check if this should count as another item.
if (item.getLinkedItemId() != -1)
{
// Ensure the linked item panel is created even if there are none in bank.
CriticalItem linked = CriticalItem.getByItemId(item.getLinkedItemId());
if (!criticalMap.containsKey(linked))
{
createItemPanel(linked);
}
// One activity and rewards no xp ignore.
if (activities.size() == 1 && activities.get(0).getXp() <= 0)
{
return;
}
}
// If it doesn't have any activities ignore it in the breakdown.
if (activities.size() <= 0)
{
return;
}
// Either this item has multiple activities or the single activity rewards xp, create the item panel.
// Determine xp rate for this item
Activity a = getSelectedActivity(item);
double activityXp = a == null ? 0 : a.getXp();
double xp = activityXp * (item.isIgnoreBonus() ? 1.0f : xpFactor);
int amount = 0;
// If it has linked items figure out the working total.
Map<CriticalItem, Integer> links = getLinkedTotalMap(item);
for (Integer num : links.values())
{
amount += num;
}
// Actually create the panel displaying banked experience for this item
CriticalItemPanel panel = new CriticalItemPanel(this, itemManager, item, xp, amount, links);
// Limit to Banked Secondaries
if (config.limitedBankedSecondaries() && a != null)
{
panel.updateAmount(limitToActivitySecondaries(a, amount), true);
panel.recalculate();
}
panelMap.put(item, panel);
detailContainer.add(panel);
}
}
/**
* Return the Activity the player selected for this Item. Defaults to First activity
*
* @param i CriticalItem to check for
* @return selected Activity
*/
public Activity getSelectedActivity(CriticalItem i)
{
// Pull from memory if available
Activity a = activityMap.get(i);
if (a != null)
{
return a;
}
// If not in memory select the first Activity and add to memory
List<Activity> activities = Activity.getByCriticalItem(i);
if (activities.size() == 0)
{
// If you can't find an activity it means this item must link to one and give 0 xp
return null;
}
Activity selected = activities.get(0);
activityMap.put(i, selected);
return selected;
}
/**
* Creates a Map of Item ID and QTY for this Skill by Category. Keeps order for better UI display
*
* @return Map of Item ID and QTY for this Skill by Category
*/
private Map<CriticalItem, Integer> getBankedXpBreakdown()
{
Map<CriticalItem, Integer> map = new LinkedHashMap<>();
for (String category : CriticalItem.getSkillCategories(currentSkill))
{
List<CriticalItem> items = CriticalItem.getItemsForSkillCategories(currentSkill, category);
for (CriticalItem item : items)
{
Integer amount = bankMap.get(item.getItemID());
if (amount != null && amount > 0)
{
map.put(item, amount);
}
}
}
return map;
}
/**
* Used to select an Activity for an item
*
* @param i CriticalItem
* @param a Activity selected
*/
public void activitySelected(CriticalItem i, Activity a)
{
// This is triggered on every click so don't update if activity didn't actually change
Activity cur = activityMap.get(i);
if (cur != null && cur.equals(a))
{
return;
}
// Update selected activity in map
activityMap.put(i, a);
// If had a previous selection and this item links to another check for item prevention change.
// If there are changes adjust the Linked panel quantity as well
if (cur != null && i.getLinkedItemId() != -1 && cur.isPreventLinked() != a.isPreventLinked())
{
CriticalItem linked = CriticalItem.getByItemId(i.getLinkedItemId());
CriticalItemPanel l = panelMap.get(linked);
if (l != null)
{
l.updateLinkedMap(getLinkedTotalMap(linked));
int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, l.getAmount()) : l.getAmount();
l.updateAmount(amount, false);
l.recalculate();
}
}
// Total banked experience
CriticalItemPanel p = panelMap.get(i);
if (p != null)
{
p.updateLinkedMap(getLinkedTotalMap(i));
int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, p.getAmount()) : p.getAmount();
p.updateAmount(amount, true);
p.updateXp(a.getXp() * (i.isIgnoreBonus() ? 1.0f : xpFactor));
}
// Update total banked xp value based on updated panels
calculateBankedXpTotal();
}
private Map<CriticalItem, Integer> getLinkedTotalMap(CriticalItem i)
{
return getLinkedTotalMap(i, true);
}
/**
* Creates a Map of CriticalItem and Qty for all items that link to the passed CriticalItem
*
* @param i CriticalItem to base Map off of
* @param first Since this is called recursively we want to ensure the original CriticalItem is always added
* @return Map of Linked CriticalItems and their Qty
*/
private Map<CriticalItem, Integer> getLinkedTotalMap(CriticalItem i, boolean first)
{
Map<CriticalItem, Integer> map = new LinkedHashMap<>();
if (!categoryMap.get(i.getCategory()))
{
return map;
}
// This item has an activity selected and its preventing linked functionality?
Activity selected = activityMap.get(i);
if (selected != null && selected.isPreventLinked()
// If initial request is for this item
&& !first)
{
return map;
}
// Add self to map
int amount = criticalMap.getOrDefault(i, 0);
if (amount > 0)
{
map.put(i, amount);
}
// This item doesn't link to anything, all done.
if (linkedMap.get(i) == null)
{
return map;
}
CriticalItem item = CriticalItem.getByItemId(linkedMap.get(i));
if (item == null)
{
log.warn("Error finding Critical Item for Item ID: {}", linkedMap.get(i));
return map;
}
map.putAll(getLinkedTotalMap(item, false));
return map;
}
/**
* SkillCalculatorPlugin sends the Bank Map when the bank contents change
*
* @param map Map of Item IDs and Quantity
*/
void updateBankMap(Map<Integer, Integer> map)
{
boolean oldMapFlag = (bankMap.size() <= 0);
bankMap = map;
// Refresh entire panel if old map was empty
if (oldMapFlag)
{
CalculatorType calc = CalculatorType.getBySkill(currentSkill);
SwingUtilities.invokeLater(() ->
{
if (calc != null)
{
openBanked(calc);
}
});
return;
}
// recalculate all data related to banked experience except for activity selections
criticalMap.clear();
linkedMap.clear();
calculatedBankedMaps();
// Update the Total XP banked and the details panel
SwingUtilities.invokeLater(this::refreshDetailContainer);
}
/**
* Loops over all ItemPanels too sum their total xp and updates the label with the new value
*/
private void calculateBankedXpTotal()
{
double total = 0.0;
for (CriticalItemPanel p : panelMap.values())
{
total += p.getTotal();
}
totalBankedXp = total;
syncBankedXp();
}
/**
* Used to update the UI to reflect the new Banked XP amount
*/
private void syncBankedXp()
{
totalLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(totalBankedXp));
syncInputFields();
revalidate();
repaint();
}
/**
* Check Bank for Activity Secondaries and Limits to possible Activity amounts
*
* @param a Selected Activity
* @param possible Amount of Critical Item available
* @return possible Limited to Banked Secondaries
*/
private int limitToActivitySecondaries(Activity a, int possible)
{
for (SecondaryItem i : a.getSecondaries())
{
int banked = bankMap.getOrDefault(i.getId(), 0);
int newPossible = banked / i.getQty();
possible = newPossible < possible ? newPossible : possible;
}
return possible;
}
/**
* Renders the Xp Modifier options
*/
private void renderBonusXpOptions()
{
SkillDataBonus[] bonuses = skillData.getSkillData(currentCalc.getDataFile()).getBonuses();
if (bonuses != null)
{
add(new JLabel("Bonus Experience:"));
for (SkillDataBonus bonus : bonuses)
{
JPanel checkboxPanel = buildCheckboxPanel(bonus);
add(checkboxPanel);
add(Box.createRigidArea(new Dimension(0, 5)));
}
}
}
private JPanel buildCheckboxPanel(SkillDataBonus bonus)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(bonus.getName());
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// Adjust XP bonus depending on check-state of the boxes.
uiCheckbox.addActionListener(event -> adjustCheckboxes(uiCheckbox, bonus));
uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(uiCheckbox, BorderLayout.EAST);
bonusCheckBoxes.add(uiCheckbox);
return uiOption;
}
private void adjustCheckboxes(JCheckBox target, SkillDataBonus bonus)
{
adjustXPBonus(0);
bonusCheckBoxes.forEach(otherSelectedCheckbox ->
{
if (otherSelectedCheckbox != target)
{
otherSelectedCheckbox.setSelected(false);
}
});
if (target.isSelected())
{
adjustXPBonus(bonus.getValue());
}
}
private void adjustXPBonus(float value)
{
xpFactor = 1f + value;
refreshDetailContainer();
}
}

View File

@@ -35,7 +35,7 @@ class CacheSkillData
{ {
private final Map<String, SkillData> cache = new HashMap<>(); private final Map<String, SkillData> cache = new HashMap<>();
SkillData getSkillData(final String dataFile) SkillData getSkillData(String dataFile)
{ {
if (cache.containsKey(dataFile)) if (cache.containsKey(dataFile))
{ {

View File

@@ -1,6 +1,5 @@
/* /*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com> * Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -25,47 +24,32 @@
*/ */
package net.runelite.client.plugins.skillcalculator; package net.runelite.client.plugins.skillcalculator;
import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.Skill; import net.runelite.api.Skill;
@AllArgsConstructor @AllArgsConstructor
@Getter(AccessLevel.PACKAGE) @Getter
public enum CalculatorType enum CalculatorType
{ {
AGILITY(Skill.AGILITY, "skill_agility.json", false), MINING(Skill.MINING, "skill_mining.json"),
CONSTRUCTION(Skill.CONSTRUCTION, "skill_construction.json", true), AGILITY(Skill.AGILITY, "skill_agility.json"),
COOKING(Skill.COOKING, "skill_cooking.json", true), SMITHING(Skill.SMITHING, "skill_smithing.json"),
CRAFTING(Skill.CRAFTING, "skill_crafting.json", true), HERBLORE(Skill.HERBLORE, "skill_herblore.json"),
FARMING(Skill.FARMING, "skill_farming.json", true), FISHING(Skill.FISHING, "skill_fishing.json"),
FIREMAKING(Skill.FIREMAKING, "skill_firemaking.json", false), THIEVING(Skill.THIEVING, "skill_thieving.json"),
FLETCHING(Skill.FLETCHING, "skill_fletching.json", false), COOKING(Skill.COOKING, "skill_cooking.json"),
FISHING(Skill.FISHING, "skill_fishing.json", false), PRAYER(Skill.PRAYER, "skill_prayer.json"),
HERBLORE(Skill.HERBLORE, "skill_herblore.json", true), CRAFTING(Skill.CRAFTING, "skill_crafting.json"),
HUNTER(Skill.HUNTER, "skill_hunter.json", false), FIREMAKING(Skill.FIREMAKING, "skill_firemaking.json"),
MAGIC(Skill.MAGIC, "skill_magic.json", false), MAGIC(Skill.MAGIC, "skill_magic.json"),
MINING(Skill.MINING, "skill_mining.json", false), FLETCHING(Skill.FLETCHING, "skill_fletching.json"),
PRAYER(Skill.PRAYER, "skill_prayer.json", true), WOODCUTTING(Skill.WOODCUTTING, "skill_woodcutting.json"),
RUNECRAFT(Skill.RUNECRAFT, "skill_runecraft.json", false), RUNECRAFT(Skill.RUNECRAFT, "skill_runecraft.json"),
SMITHING(Skill.SMITHING, "skill_smithing.json", true), FARMING(Skill.FARMING, "skill_farming.json"),
THIEVING(Skill.THIEVING, "skill_thieving.json", false), CONSTRUCTION(Skill.CONSTRUCTION, "skill_construction.json"),
WOODCUTTING(Skill.WOODCUTTING, "skill_woodcutting.json", false); HUNTER(Skill.HUNTER, "skill_hunter.json");
private final Skill skill; private final Skill skill;
private final String dataFile; private final String dataFile;
private final boolean bankedXpFlag;
public static CalculatorType getBySkill(Skill skill)
{
for (CalculatorType c : values())
{
if (c.getSkill().equals(skill))
{
return c;
}
}
return null;
}
} }

View File

@@ -34,18 +34,13 @@ import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import javax.inject.Singleton;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Experience; import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager; import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.skillcalculator.beans.SkillData; import net.runelite.client.plugins.skillcalculator.beans.SkillData;
@@ -59,7 +54,6 @@ import net.runelite.client.ui.components.IconTextField;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@Singleton
class SkillCalculator extends JPanel class SkillCalculator extends JPanel
{ {
private static final int MAX_XP = 200_000_000; private static final int MAX_XP = 200_000_000;
@@ -71,9 +65,7 @@ class SkillCalculator extends JPanel
private final ItemManager itemManager; private final ItemManager itemManager;
private final List<UIActionSlot> uiActionSlots = new ArrayList<>(); private final List<UIActionSlot> uiActionSlots = new ArrayList<>();
private final CacheSkillData cacheSkillData = new CacheSkillData(); private final CacheSkillData cacheSkillData = new CacheSkillData();
@Getter(AccessLevel.PACKAGE)
private final UICombinedActionSlot combinedActionSlot; private final UICombinedActionSlot combinedActionSlot;
@Getter(AccessLevel.PACKAGE)
private final List<UIActionSlot> combinedActionSlots = new ArrayList<>(); private final List<UIActionSlot> combinedActionSlots = new ArrayList<>();
private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>(); private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>();
private final IconTextField searchBar = new IconTextField(); private final IconTextField searchBar = new IconTextField();
@@ -85,9 +77,8 @@ class SkillCalculator extends JPanel
private int targetXP = Experience.getXpForLevel(targetLevel); private int targetXP = Experience.getXpForLevel(targetLevel);
private float xpFactor = 1.0f; private float xpFactor = 1.0f;
private float lastBonus = 0.0f; private float lastBonus = 0.0f;
private CalculatorType calculatorType;
SkillCalculator(final Client client, final UICalculatorInputArea uiInput, final SpriteManager spriteManager, final ItemManager itemManager) SkillCalculator(Client client, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager)
{ {
this.client = client; this.client = client;
this.uiInput = uiInput; this.uiInput = uiInput;
@@ -123,8 +114,6 @@ class SkillCalculator extends JPanel
void openCalculator(CalculatorType calculatorType) void openCalculator(CalculatorType calculatorType)
{ {
this.calculatorType = calculatorType;
// Load the skill data. // Load the skill data.
skillData = cacheSkillData.getSkillData(calculatorType.getDataFile()); skillData = cacheSkillData.getSkillData(calculatorType.getDataFile());
@@ -132,11 +121,10 @@ class SkillCalculator extends JPanel
xpFactor = 1.0f; xpFactor = 1.0f;
// Update internal skill/XP values. // Update internal skill/XP values.
updateInternalValues(); currentXP = client.getSkillExperience(calculatorType.getSkill());
currentLevel = Experience.getLevelForXp(currentXP);
// BankedCalculator prevents these from being editable so just ensure they are editable. targetLevel = enforceSkillBounds(currentLevel + 1);
uiInput.getUiFieldTargetLevel().setEditable(true); targetXP = Experience.getXpForLevel(targetLevel);
uiInput.getUiFieldTargetXP().setEditable(true);
// Remove all components (action slots) from this panel. // Remove all components (action slots) from this panel.
removeAll(); removeAll();
@@ -144,9 +132,6 @@ class SkillCalculator extends JPanel
// Clear the search bar // Clear the search bar
searchBar.setText(null); searchBar.setText(null);
// Clear the search bar
searchBar.setText(null);
// Add in checkboxes for available skill bonuses. // Add in checkboxes for available skill bonuses.
renderBonusOptions(); renderBonusOptions();
@@ -163,24 +148,6 @@ class SkillCalculator extends JPanel
updateInputFields(); updateInputFields();
} }
private void updateInternalValues()
{
updateCurrentValues();
updateTargetValues();
}
private void updateCurrentValues()
{
currentXP = client.getSkillExperience(calculatorType.getSkill());
currentLevel = Experience.getLevelForXp(currentXP);
}
private void updateTargetValues()
{
targetLevel = enforceSkillBounds(currentLevel + 1);
targetXP = Experience.getXpForLevel(targetLevel);
}
private void updateCombinedAction() private void updateCombinedAction()
{ {
int size = combinedActionSlots.size(); int size = combinedActionSlots.size();
@@ -254,7 +221,7 @@ class SkillCalculator extends JPanel
JCheckBox uiCheckbox = new JCheckBox(); JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE); uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getSmallFont(getFont())); uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -270,7 +237,7 @@ class SkillCalculator extends JPanel
for (JCheckBox checkBox : uiCheckBoxList) for (JCheckBox checkBox : uiCheckBoxList)
{ {
if (checkBox != null && !checkBox.equals(uiCheckBox)) if (checkBox != uiCheckBox)
{ {
checkBox.setSelected(false); checkBox.setSelected(false);
} }
@@ -466,25 +433,4 @@ class SkillCalculator extends JPanel
return slot.getAction().getName().toLowerCase().contains(text.toLowerCase()); return slot.getAction().getName().toLowerCase().contains(text.toLowerCase());
} }
/**
* Updates the current skill calculator (if present)
* <p>
* This method is invoked by the {@link SkillCalculatorPlugin} event subscriber
* when an {@link ExperienceChanged} object is posted to the event bus
*/
void updateSkillCalculator(Skill skill)
{
// If the user has selected a calculator, update its fields
Optional.ofNullable(calculatorType).ifPresent(calc ->
{
if (skill.equals(calculatorType.getSkill()))
{
// Update our model "current" values
updateCurrentValues();
// Update the UI to reflect our new model
updateInputFields();
}
});
}
} }

View File

@@ -32,24 +32,24 @@ import net.runelite.client.config.ConfigItem;
public interface SkillCalculatorConfig extends Config public interface SkillCalculatorConfig extends Config
{ {
@ConfigItem( @ConfigItem(
keyName = "showBankedXp", keyName = "enabledBankedXp",
name = "Show Banked xp Tab", name = "Add Banked XP Panel",
description = "Shows the Banked xp tab inside the Calculator Panel", description = "Adds the Banked XP Panel to the side bar",
position = 0 position = 0
) )
default boolean showBankedXp() default boolean showBankedXp()
{ {
return true; return false;
} }
@ConfigItem( @ConfigItem(
keyName = "limitedBankedSecondaries", keyName = "cascadeBankedXp",
name = "Limit Banked xp to Secondaries", name = "Include output items",
description = "Limits the Banked xp shown based on secondaries banked as well", description = "Includes output items in the item quantity calculations",
position = 1 position = 1
) )
default boolean limitedBankedSecondaries() default boolean cascadeBankedXp()
{ {
return false; return true;
} }
} }

View File

@@ -1,7 +1,6 @@
/* /*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com> * Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, Psikoi <https://github.com/psikoi> * Copyright (c) 2018, Psikoi <https://github.com/psikoi>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -30,20 +29,10 @@ package net.runelite.client.plugins.skillcalculator;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Singleton;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager; import net.runelite.client.game.SkillIconManager;
import net.runelite.client.game.SpriteManager; import net.runelite.client.game.SpriteManager;
@@ -52,43 +41,30 @@ import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.materialtabs.MaterialTab; import net.runelite.client.ui.components.materialtabs.MaterialTab;
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
@Slf4j
@Singleton
class SkillCalculatorPanel extends PluginPanel class SkillCalculatorPanel extends PluginPanel
{ {
private final SkillCalculator uiCalculator; private final SkillCalculator uiCalculator;
private final SkillIconManager iconManager; private final SkillIconManager iconManager;
private final SkillCalculatorConfig config;
private final BankedCalculator bankedCalculator;
private CalculatorType currentCalc;
private final MaterialTabGroup skillGroup;
private final MaterialTabGroup tabGroup; private final MaterialTabGroup tabGroup;
private String currentTab;
private final List<String> tabs = new ArrayList<>();
@Getter
private Map<Integer, Integer> bankMap = new HashMap<>();
private final GridBagConstraints c;
SkillCalculatorPanel(final SkillIconManager iconManager, final Client client, final SkillCalculatorConfig config, final SpriteManager spriteManager, final ItemManager itemManager) SkillCalculatorPanel(SkillIconManager iconManager, Client client, SpriteManager spriteManager, ItemManager itemManager)
{ {
super(); super();
getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.iconManager = iconManager; this.iconManager = iconManager;
this.config = config;
setBorder(new EmptyBorder(10, 10, 10, 10)); setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout()); setLayout(new GridBagLayout());
c = new GridBagConstraints(); GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL; c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1; c.weightx = 1;
c.gridx = 0; c.gridx = 0;
c.gridy = 0; c.gridy = 0;
skillGroup = new MaterialTabGroup(); tabGroup = new MaterialTabGroup();
skillGroup.setLayout(new GridLayout(0, 6, 7, 7)); tabGroup.setLayout(new GridLayout(0, 6, 7, 7));
addCalculatorButtons(); addCalculatorButtons();
@@ -97,23 +73,14 @@ class SkillCalculatorPanel extends PluginPanel
uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR); uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR);
uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager); uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager);
bankedCalculator = new BankedCalculator(this, client, uiInput, config, itemManager); add(tabGroup, c);
tabGroup = new MaterialTabGroup();
tabGroup.setBorder(new EmptyBorder(0, 0, 10, 0));
addTabButtons();
add(skillGroup, c);
c.gridy++; c.gridy++;
add(uiInput, c); add(uiInput, c);
c.gridy++; c.gridy++;
add(tabGroup, c);
c.gridy++;
add(uiCalculator, c); add(uiCalculator, c);
c.gridy++;
} }
private void addCalculatorButtons() private void addCalculatorButtons()
@@ -121,126 +88,14 @@ class SkillCalculatorPanel extends PluginPanel
for (CalculatorType calculatorType : CalculatorType.values()) for (CalculatorType calculatorType : CalculatorType.values())
{ {
ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true)); ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true));
MaterialTab tab = new MaterialTab(icon, skillGroup, null); MaterialTab tab = new MaterialTab(icon, tabGroup, null);
tab.setOnSelectEvent(() -> tab.setOnSelectEvent(() ->
{ {
if (currentCalc != null && currentCalc.equals(calculatorType)) uiCalculator.openCalculator(calculatorType);
{
return true;
}
currentCalc = calculatorType;
selectedTab(currentTab, true);
return true; return true;
}); });
skillGroup.addTab(tab); tabGroup.addTab(tab);
} }
} }
private void addTabButtons()
{
tabGroup.removeAll();
tabs.clear();
tabs.add("Calculator");
if (config.showBankedXp())
{
tabs.add("Banked Xp");
}
// Only show if both options are visible
tabGroup.setVisible(tabs.size() > 1);
tabGroup.setLayout(new GridLayout(0, tabs.size(), 7, 7));
for (String s : tabs)
{
MaterialTab matTab = new MaterialTab(s, tabGroup, null);
matTab.setHorizontalAlignment(SwingUtilities.CENTER);
// Ensure Background is applied
matTab.setOpaque(true);
matTab.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// When Clicked
matTab.setOnSelectEvent(() ->
{
selectedTab(s, false);
return true;
});
tabGroup.addTab(matTab);
}
MaterialTab selected = tabGroup.getTab(0);
if (tabs.contains(currentTab))
{
selected = tabGroup.getTab(tabs.indexOf(currentTab));
}
tabGroup.select(selected);
currentTab = selected.getText();
}
private void selectedTab(String s, boolean force)
{
// Do not refresh the panel if they clicked the same tab, unless they selected a new skill
if (Objects.equals(currentTab, s) && !force)
{
return;
}
currentTab = s;
// Only open a panel if a skill is selected
if (currentCalc == null)
{
return;
}
switch (s)
{
case "Calculator":
remove(bankedCalculator);
add(uiCalculator, c);
uiCalculator.openCalculator(currentCalc);
break;
case "Banked Xp":
remove(uiCalculator);
add(bankedCalculator, c);
bankedCalculator.openBanked(currentCalc);
break;
}
this.revalidate();
this.repaint();
}
// Refresh entire panel
void refreshPanel()
{
// Recreate Tabs (in case of Config change) and selects the first tab
addTabButtons();
// Ensure reload
selectedTab(currentTab, true);
this.revalidate();
this.repaint();
}
// Wrapper function for updating SkillCalculator's bankMap
void updateBankMap(Map<Integer, Integer> bank)
{
bankMap = bank;
if (currentCalc != null & currentTab.equals("Banked Xp"))
{
bankedCalculator.updateBankMap(bankMap);
}
}
void updateSkillCalculator(Skill skill)
{
uiCalculator.updateSkillCalculator(skill);
}
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com> * Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle> * Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -31,18 +31,13 @@ import java.awt.image.BufferedImage;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import lombok.Getter;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.InventoryID; import net.runelite.api.InventoryID;
import net.runelite.api.Item; import net.runelite.api.Item;
import net.runelite.api.ItemContainer; import net.runelite.api.ItemContainer;
import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ExperienceChanged; import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
@@ -51,7 +46,9 @@ import net.runelite.client.game.SkillIconManager;
import net.runelite.client.game.SpriteManager; import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; import net.runelite.client.plugins.skillcalculator.banked.BankedCalculatorPanel;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
@@ -61,7 +58,6 @@ import net.runelite.client.util.ImageUtil;
description = "Enable the Skill Calculator panel", description = "Enable the Skill Calculator panel",
tags = {"panel", "skilling"} tags = {"panel", "skilling"}
) )
@Singleton
public class SkillCalculatorPlugin extends Plugin public class SkillCalculatorPlugin extends Plugin
{ {
@Inject @Inject
@@ -86,12 +82,10 @@ public class SkillCalculatorPlugin extends Plugin
private SkillCalculatorConfig skillCalculatorConfig; private SkillCalculatorConfig skillCalculatorConfig;
private NavigationButton uiNavigationButton; private NavigationButton uiNavigationButton;
private SkillCalculatorPanel uiPanel; private NavigationButton bankedUiNavigationButton;
@Getter private BankedCalculatorPanel bankedUiPanel;
private Map<Integer, Integer> bankMap = new HashMap<>(); private int bankHash = -1;
private int bankHash;
@Provides @Provides
SkillCalculatorConfig getConfig(ConfigManager configManager) SkillCalculatorConfig getConfig(ConfigManager configManager)
@@ -103,7 +97,7 @@ public class SkillCalculatorPlugin extends Plugin
protected void startUp() throws Exception protected void startUp() throws Exception
{ {
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "calc.png"); final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "calc.png");
this.uiPanel = new SkillCalculatorPanel(skillIconManager, client, skillCalculatorConfig, spriteManager, itemManager); final SkillCalculatorPanel uiPanel = new SkillCalculatorPanel(skillIconManager, client, spriteManager, itemManager);
uiNavigationButton = NavigationButton.builder() uiNavigationButton = NavigationButton.builder()
.tooltip("Skill Calculator") .tooltip("Skill Calculator")
@@ -114,56 +108,32 @@ public class SkillCalculatorPlugin extends Plugin
clientToolbar.addNavigation(uiNavigationButton); clientToolbar.addNavigation(uiNavigationButton);
clientThread.invokeLater(() -> toggleBankedXpPanel();
{
switch (client.getGameState())
{
case STARTING:
case UNKNOWN:
return false;
}
CriticalItem.prepareItemDefinitions(itemManager);
return true;
});
} }
@Override @Override
protected void shutDown() throws Exception protected void shutDown() throws Exception
{ {
clientToolbar.removeNavigation(uiNavigationButton); clientToolbar.removeNavigation(uiNavigationButton);
bankMap.clear(); if (bankedUiNavigationButton != null)
bankHash = -1; {
clientToolbar.removeNavigation(bankedUiNavigationButton);
}
} }
@Subscribe @Subscribe
public void onConfigChanged(ConfigChanged event) public void onConfigChanged(ConfigChanged event)
{ {
if (event.getGroup().equals("skillCalculator")) if (event.getGroup().equals("skillCalculator") && event.getKey().equals("enabledBankedXp"))
{ {
if (event.getKey().equals("showBankedXp")) toggleBankedXpPanel();
{
bankMap.clear();
bankHash = -1;
}
SwingUtilities.invokeLater(() -> uiPanel.refreshPanel());
} }
} }
// Pulled from bankvalue plugin to check if bank is open
@Subscribe @Subscribe
public void onGameTick(GameTick event) public void onScriptCallbackEvent(ScriptCallbackEvent event)
{ {
if (!skillCalculatorConfig.showBankedXp()) if (!event.getEventName().equals("setBankTitle") || !skillCalculatorConfig.showBankedXp())
{
return;
}
Widget widgetBankTitleBar = client.getWidget(WidgetInfo.BANK_TITLE_BAR);
// Don't update on a search because rs seems to constantly update the title
if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden() || widgetBankTitleBar.getText().contains("Showing"))
{ {
return; return;
} }
@@ -171,54 +141,80 @@ public class SkillCalculatorPlugin extends Plugin
updateBankItems(); updateBankItems();
} }
private void toggleBankedXpPanel()
{
if (skillCalculatorConfig.showBankedXp())
{
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "banked.png");
bankedUiPanel = new BankedCalculatorPanel(client, skillCalculatorConfig, skillIconManager, itemManager);
bankedUiNavigationButton = NavigationButton.builder()
.tooltip("Banked XP")
.icon(icon)
.priority(6)
.panel(bankedUiPanel)
.build();
clientToolbar.addNavigation(bankedUiNavigationButton);
clientThread.invoke(() ->
{
switch (client.getGameState())
{
case LOGIN_SCREEN:
case LOGIN_SCREEN_AUTHENTICATOR:
case LOGGING_IN:
case LOADING:
case LOGGED_IN:
case CONNECTION_LOST:
case HOPPING:
CriticalItem.prepareItemDefinitions(itemManager);
Activity.prepareItemDefinitions(itemManager);
return true;
default:
return false;
}
});
}
else
{
if (bankedUiNavigationButton == null)
{
return;
}
clientToolbar.removeNavigation(bankedUiNavigationButton);
bankedUiNavigationButton = null;
}
}
// Check if bank contents changed and if so send to UI // Check if bank contents changed and if so send to UI
private void updateBankItems() private void updateBankItems()
{ {
ItemContainer c = client.getItemContainer(InventoryID.BANK); final ItemContainer c = client.getItemContainer(InventoryID.BANK);
Item[] widgetItems = (c == null ? new Item[0] : c.getItems()); if (c == null)
{
return;
}
// Couldn't find any items in bank, do nothing. final Item[] widgetItems = c.getItems();
if (widgetItems == null || widgetItems.length == 0) if (widgetItems == null || widgetItems.length == 0)
{ {
return; return;
} }
Map<Integer, Integer> newBankMap = getBankMapIfDiff(widgetItems); final Map<Integer, Integer> m = new HashMap<>();
// Bank didn't change
if (newBankMap.size() == 0)
{
return;
}
bankMap = newBankMap;
// send updated bank map to ui
uiPanel.updateBankMap(bankMap);
}
// Recreates the bankMap and checks if the hashCode is different (the map has changed). Sends an empty map if no changes
private Map<Integer, Integer> getBankMapIfDiff(Item[] widgetItems)
{
Map<Integer, Integer> mapCheck = new HashMap<>();
for (Item widgetItem : widgetItems) for (Item widgetItem : widgetItems)
{ {
mapCheck.put(widgetItem.getId(), widgetItem.getQuantity()); m.put(widgetItem.getId(), widgetItem.getQuantity());
} }
int curHash = mapCheck.hashCode(); final int curHash = m.hashCode();
if (bankHash != curHash)
if (curHash != bankHash)
{ {
bankHash = curHash; bankHash = curHash;
return mapCheck; SwingUtilities.invokeLater(() -> bankedUiPanel.setBankMap(m));
} }
return new HashMap<>();
}
@Subscribe
public void onExperienceChanged(ExperienceChanged changeEvent)
{
uiPanel.updateSkillCalculator(changeEvent.getSkill());
} }
} }

View File

@@ -33,7 +33,6 @@ import java.awt.GridLayout;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import javax.inject.Singleton;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -48,7 +47,6 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager; import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
@Singleton
class UIActionSlot extends JPanel class UIActionSlot extends JPanel
{ {
private static final Border GREEN_BORDER = new CompoundBorder( private static final Border GREEN_BORDER = new CompoundBorder(
@@ -127,7 +125,7 @@ class UIActionSlot extends JPanel
uiLabelName.setForeground(Color.WHITE); uiLabelName.setForeground(Color.WHITE);
uiLabelActions = new JShadowedLabel("Unknown"); uiLabelActions = new JShadowedLabel("Unknown");
uiLabelActions.setFont(FontManager.getSmallFont(getFont())); uiLabelActions.setFont(FontManager.getRunescapeSmallFont());
uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR); uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
uiInfo.add(uiLabelName); uiInfo.add(uiLabelName);

View File

@@ -28,27 +28,24 @@ package net.runelite.client.plugins.skillcalculator;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.GridLayout; import java.awt.GridLayout;
import javax.inject.Singleton;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager; import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.FlatTextField; import net.runelite.client.ui.components.FlatTextField;
@Getter(AccessLevel.PACKAGE) @Getter
@Singleton public class UICalculatorInputArea extends JPanel
class UICalculatorInputArea extends JPanel
{ {
private final JTextField uiFieldCurrentLevel; private final JTextField uiFieldCurrentLevel;
private final JTextField uiFieldCurrentXP; private final JTextField uiFieldCurrentXP;
private final JTextField uiFieldTargetLevel; private final JTextField uiFieldTargetLevel;
private final JTextField uiFieldTargetXP; private final JTextField uiFieldTargetXP;
UICalculatorInputArea() public UICalculatorInputArea()
{ {
setLayout(new GridLayout(2, 2, 7, 7)); setLayout(new GridLayout(2, 2, 7, 7));
uiFieldCurrentLevel = addComponent("Current Level"); uiFieldCurrentLevel = addComponent("Current Level");
@@ -62,7 +59,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldCurrentLevel); return getInput(uiFieldCurrentLevel);
} }
void setCurrentLevelInput(int value) public void setCurrentLevelInput(int value)
{ {
setInput(uiFieldCurrentLevel, value); setInput(uiFieldCurrentLevel, value);
} }
@@ -72,7 +69,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldCurrentXP); return getInput(uiFieldCurrentXP);
} }
void setCurrentXPInput(Object value) public void setCurrentXPInput(Object value)
{ {
setInput(uiFieldCurrentXP, value); setInput(uiFieldCurrentXP, value);
} }
@@ -82,7 +79,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldTargetLevel); return getInput(uiFieldTargetLevel);
} }
void setTargetLevelInput(Object value) public void setTargetLevelInput(Object value)
{ {
setInput(uiFieldTargetLevel, value); setInput(uiFieldTargetLevel, value);
} }
@@ -92,7 +89,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldTargetXP); return getInput(uiFieldTargetXP);
} }
void setTargetXPInput(Object value) public void setTargetXPInput(Object value)
{ {
setInput(uiFieldTargetXP, value); setInput(uiFieldTargetXP, value);
} }
@@ -126,7 +123,7 @@ class UICalculatorInputArea extends JPanel
uiInput.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); uiInput.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
uiInput.setBorder(new EmptyBorder(5, 7, 5, 7)); uiInput.setBorder(new EmptyBorder(5, 7, 5, 7));
uiLabel.setFont(FontManager.getSmallFont(getFont())); uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiLabel.setBorder(new EmptyBorder(0, 0, 4, 0)); uiLabel.setBorder(new EmptyBorder(0, 0, 4, 0));
uiLabel.setForeground(Color.WHITE); uiLabel.setForeground(Color.WHITE);
@@ -137,4 +134,4 @@ class UICalculatorInputArea extends JPanel
return uiInput.getTextField(); return uiInput.getTextField();
} }
} }

View File

@@ -30,7 +30,6 @@ import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.GridLayout; import java.awt.GridLayout;
import javax.inject.Singleton;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -40,14 +39,13 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager; import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
@Singleton
class UICombinedActionSlot extends JPanel class UICombinedActionSlot extends JPanel
{ {
private static final Dimension ICON_SIZE = new Dimension(32, 32); private static final Dimension ICON_SIZE = new Dimension(32, 32);
private final JShadowedLabel uiLabelActions; private final JShadowedLabel uiLabelActions;
private final JShadowedLabel uiLabelTitle; private final JShadowedLabel uiLabelTitle;
UICombinedActionSlot(final SpriteManager spriteManager) UICombinedActionSlot(SpriteManager spriteManager)
{ {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
setBackground(ColorScheme.DARKER_GRAY_COLOR); setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -70,7 +68,7 @@ class UICombinedActionSlot extends JPanel
uiLabelTitle.setForeground(Color.WHITE); uiLabelTitle.setForeground(Color.WHITE);
uiLabelActions = new JShadowedLabel("Shift-click to select multiple"); uiLabelActions = new JShadowedLabel("Shift-click to select multiple");
uiLabelActions.setFont(FontManager.getSmallFont(getFont())); uiLabelActions.setFont(FontManager.getRunescapeSmallFont());
uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR); uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
uiInfo.add(uiLabelTitle); uiInfo.add(uiLabelTitle);

View File

@@ -0,0 +1,462 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.SkillCalculatorConfig;
import net.runelite.client.plugins.skillcalculator.UICalculatorInputArea;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.XpModifiers;
import net.runelite.client.plugins.skillcalculator.banked.components.GridItem;
import net.runelite.client.plugins.skillcalculator.banked.components.ModifyPanel;
import net.runelite.client.plugins.skillcalculator.banked.components.SelectionGrid;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@Slf4j
public class BankedCalculator extends JPanel
{
public static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#");
private final Client client;
@Getter
private final SkillCalculatorConfig config;
private final UICalculatorInputArea uiInput;
private final ItemManager itemManager;
// Some activities output a CriticalItem and may need to be included in the calculable qty
// Using multimap for cases where there are multiple items linked directly to one item, use recursion for otherwise
private final Multimap<CriticalItem, BankedItem> linkedMap = ArrayListMultimap.create();
private final Map<CriticalItem, BankedItem> bankedItemMap = new LinkedHashMap<>();
private final JLabel totalXpLabel = new JLabel();
private final ModifyPanel modifyPanel;
private SelectionGrid itemGrid;
@Setter
private Map<Integer, Integer> bankMap = new HashMap<>();
@Getter
private Skill currentSkill;
@Getter
private int skillLevel, skillExp, endLevel, endExp;
private final Collection<JCheckBox> xpModifierButtons = new ArrayList<>();
@Getter
private float xpFactor = 1.0f;
BankedCalculator(UICalculatorInputArea uiInput, Client client, SkillCalculatorConfig config, ItemManager itemManager)
{
this.uiInput = uiInput;
this.client = client;
this.config = config;
this.itemManager = itemManager;
setLayout(new DynamicGridLayout(0, 1, 0, 5));
// Panel used to modify banked item values
this.modifyPanel = new ModifyPanel(this, itemManager);
}
/**
* opens the Banked Calculator for this skill
*/
void open(final Skill newSkill)
{
if (newSkill.equals(currentSkill))
{
return;
}
this.currentSkill = newSkill;
removeAll();
xpFactor = 1.0f;
if (bankMap.size() <= 0)
{
add(new JLabel("Please visit a bank!", JLabel.CENTER));
revalidate();
repaint();
return;
}
skillLevel = client.getRealSkillLevel(currentSkill);
skillExp = client.getSkillExperience(currentSkill);
endLevel = skillLevel;
endExp = skillExp;
uiInput.setCurrentLevelInput(skillLevel);
uiInput.setCurrentXPInput(skillExp);
uiInput.setTargetLevelInput(endLevel);
uiInput.setTargetXPInput(endExp);
recreateBankedItemMap();
final Collection<XpModifiers> modifiers = XpModifiers.getModifiersBySkill(this.currentSkill);
for (final XpModifiers modifier : modifiers)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(modifier.getName());
JCheckBox btn = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiLabel.setHorizontalAlignment(SwingConstants.CENTER);
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
btn.addItemListener((event) ->
{
switch (event.getStateChange())
{
case ItemEvent.DESELECTED:
xpFactor = 1.0f;
break;
case ItemEvent.SELECTED:
// Deselects all but the current item
final JCheckBox box = (JCheckBox) event.getItem();
xpModifierButtons.forEach(b -> b.setSelected(b == box));
xpFactor = modifier.getModifier();
break;
default:
return;
}
modifierUpdated();
});
xpModifierButtons.add(btn);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(btn, BorderLayout.EAST);
add(uiOption);
}
recreateItemGrid();
// This should only be null if there are no items in their bank for this skill
if (itemGrid.getSelectedItem() == null)
{
add(new JLabel("Couldn't find any items for this skill.", JLabel.CENTER));
}
else
{
add(totalXpLabel);
add(modifyPanel);
add(itemGrid);
}
revalidate();
repaint();
}
private void recreateBankedItemMap()
{
bankedItemMap.clear();
linkedMap.clear();
final Collection<CriticalItem> items = CriticalItem.getBySkill(currentSkill);
log.debug("Critical Items for the {} Skill: {}", currentSkill.getName(), items);
for (final CriticalItem item : items)
{
final BankedItem banked = new BankedItem(item, bankMap.getOrDefault(item.getItemID(), 0));
bankedItemMap.put(item, banked);
Activity a = item.getSelectedActivity();
if (a == null)
{
final List<Activity> activities = Activity.getByCriticalItem(item);
if (activities.size() == 0)
{
continue;
}
item.setSelectedActivity(activities.get(0));
a = activities.get(0);
}
if (a.getLinkedItem() != null)
{
linkedMap.put(a.getLinkedItem(), banked);
}
}
log.debug("Banked Item Map: {}", bankedItemMap);
log.debug("Linked Map: {}", linkedMap);
}
/**
* Populates the detailContainer with the necessary BankedItemPanels
*/
private void recreateItemGrid()
{
// Selection grid will only display values with > 0 items
itemGrid = new SelectionGrid(this, bankedItemMap.values(), itemManager);
itemGrid.setOnSelectEvent(() ->
{
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
return true;
});
itemGrid.setOnIgnoreEvent(() ->
{
CriticalItem item = itemGrid.getLastIgnoredItem().getItem();
updateLinkedItems(item.getSelectedActivity());
calculateBankedXpTotal();
return true;
});
// Select the first item in the list
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
calculateBankedXpTotal();
}
public double getItemXpRate(final BankedItem bankedItem)
{
return bankedItem.getXpRate() * (bankedItem.getItem().isIgnoreBonus() ? 1.0f : xpFactor);
}
/**
* Calculates total item quantity accounting for backwards linked items
*
* @param item starting item
* @return item qty including linked items
*/
public int getItemQty(final BankedItem item)
{
int qty = item.getQty();
if (!config.cascadeBankedXp())
{
return qty;
}
final Map<CriticalItem, Integer> linked = createLinksMap(item);
final int linkedQty = linked.values().stream().mapToInt(Integer::intValue).sum();
return qty + linkedQty;
}
private void calculateBankedXpTotal()
{
double total = 0.0;
for (final GridItem i : itemGrid.getPanelMap().values())
{
if (i.isIgnored())
{
continue;
}
final BankedItem bi = i.getBankedItem();
total += getItemQty(bi) * getItemXpRate(bi);
}
endExp = (int) (skillExp + total);
endLevel = Experience.getLevelForXp(endExp);
totalXpLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(total));
uiInput.setTargetLevelInput(endLevel);
uiInput.setTargetXPInput(Math.min(Experience.MAX_SKILL_XP, endExp));
revalidate();
repaint();
}
/**
* Used to select an Activity for an item
*
* @param i BankedItem item the activity is tied to
* @param a Activity the selected activity
*/
public void activitySelected(final BankedItem i, final Activity a)
{
final CriticalItem item = i.getItem();
final Activity old = item.getSelectedActivity();
if (a.equals(old))
{
return;
}
item.setSelectedActivity(a);
// Cascade activity changes if necessary.
if (config.cascadeBankedXp() && (old.getLinkedItem() != a.getLinkedItem()))
{
// Update Linked Map
linkedMap.remove(old.getLinkedItem(), i);
linkedMap.put(a.getLinkedItem(), i);
// Update all items the old activity effects
updateLinkedItems(old);
// Update all the items the new activity effects
updateLinkedItems(a);
}
modifyPanel.setBankedItem(i);
itemGrid.getPanelMap().get(i).updateToolTip();
// recalculate total xp
calculateBankedXpTotal();
}
/**
* Updates the item quantities of all forward linked items
*
* @param activity the starting {@link Activity} to start the cascade from
*/
private void updateLinkedItems(final Activity activity)
{
if (activity == null)
{
return;
}
boolean foundSelected = false;
boolean panelAmountChange = false;
CriticalItem i = activity.getLinkedItem();
while (i != null)
{
final BankedItem bi = bankedItemMap.get(i);
if (bi == null)
{
break;
}
final int qty = getItemQty(bi);
final boolean stackable = bi.getItem().getItemInfo().isStackable() || qty > 1;
final AsyncBufferedImage img = itemManager.getImage(bi.getItem().getItemID(), qty, stackable);
final GridItem gridItem = itemGrid.getPanelMap().get(bi);
final int oldQty = gridItem.getAmount();
panelAmountChange = panelAmountChange || ((oldQty == 0 && qty > 0) || (oldQty > 0 && qty == 0));
gridItem.updateIcon(img, qty);
gridItem.updateToolTip();
foundSelected = foundSelected || itemGrid.getSelectedItem().equals(bi);
final Activity a = bi.getItem().getSelectedActivity();
if (a == null)
{
break;
}
i = a.getLinkedItem();
}
if (panelAmountChange)
{
itemGrid.refreshGridDisplay();
}
if (foundSelected)
{
// Refresh current modify panel if the cascade effects it
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
}
}
/**
* Creates a Map of CriticalItem to bank qty for all items that are being linked to this one
*
* @param item starting item
* @return Map of CriticalItem to bank qty
*/
public Map<CriticalItem, Integer> createLinksMap(final BankedItem item)
{
final Map<CriticalItem, Integer> qtyMap = new HashMap<>();
final Activity a = item.getItem().getSelectedActivity();
if (a == null)
{
return qtyMap;
}
final Collection<BankedItem> linkedBank = linkedMap.get(item.getItem());
if (linkedBank == null || linkedBank.size() == 0)
{
return qtyMap;
}
for (final BankedItem linked : linkedBank)
{
// Check if the item is ignored in the grid
if (itemGrid != null)
{
final GridItem grid = itemGrid.getPanelMap().get(linked);
if (grid != null && grid.isIgnored())
{
continue;
}
}
final int qty = linked.getQty();
if (qty > 0)
{
qtyMap.put(linked.getItem(), qty);
}
qtyMap.putAll(createLinksMap(linked));
}
return qtyMap;
}
private void modifierUpdated()
{
itemGrid.getPanelMap().values().forEach(GridItem::updateToolTip);
modifyPanel.setBankedItem(modifyPanel.getBankedItem());
calculateBankedXpTotal();
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked;
import com.google.common.collect.ImmutableSet;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.image.BufferedImage;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.plugins.skillcalculator.SkillCalculatorConfig;
import net.runelite.client.plugins.skillcalculator.UICalculatorInputArea;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.ComboBoxIconEntry;
import net.runelite.client.ui.components.ComboBoxListRenderer;
@Slf4j
public class BankedCalculatorPanel extends PluginPanel
{
private final static ImmutableSet<Skill> BANKABLE_SKILLS = ImmutableSet.of(
Skill.CONSTRUCTION, Skill.COOKING, Skill.CRAFTING, Skill.FARMING, Skill.HERBLORE, Skill.PRAYER, Skill.SMITHING
);
private final BankedCalculator calculator;
public BankedCalculatorPanel(Client client, SkillCalculatorConfig config, SkillIconManager skillIconManager, ItemManager itemManager)
{
super();
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
final UICalculatorInputArea inputs = new UICalculatorInputArea();
inputs.setBorder(new EmptyBorder(15, 0, 15, 0));
inputs.setBackground(ColorScheme.DARK_GRAY_COLOR);
inputs.getUiFieldTargetXP().setEditable(false);
inputs.getUiFieldTargetLevel().setEditable(false);
calculator = new BankedCalculator(inputs, client, config, itemManager);
// Create the Skill dropdown with icons
final JComboBox<ComboBoxIconEntry> dropdown = new JComboBox<>();
final ComboBoxListRenderer renderer = new ComboBoxListRenderer();
renderer.setDefaultText("Select a Skill...");
dropdown.setRenderer(renderer);
for (final Skill skill : BANKABLE_SKILLS)
{
final BufferedImage img = skillIconManager.getSkillImage(skill, true);
final ComboBoxIconEntry entry = new ComboBoxIconEntry(new ImageIcon(img), skill.getName(), skill);
dropdown.addItem(entry);
}
// Add click event handler now to prevent above code from triggering it.
dropdown.addItemListener(e ->
{
if (e.getStateChange() == ItemEvent.SELECTED)
{
final ComboBoxIconEntry source = (ComboBoxIconEntry) e.getItem();
if (source.getData() instanceof Skill)
{
final Skill skill = (Skill) source.getData();
this.calculator.open(skill);
}
}
});
dropdown.setSelectedIndex(-1);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
add(dropdown, c);
c.gridy++;
add(inputs, c);
c.gridy++;
add(calculator, c);
}
public void setBankMap(final Map<Integer, Integer> bankMap)
{
calculator.setBankMap(bankMap);
}
}

View File

@@ -1,418 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Getter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
public enum CriticalItem
{
/**
* Construction Items
*/
// Planks
PLANK(ItemID.PLANK, "Planks", Skill.CONSTRUCTION),
OAK_PLANK(ItemID.OAK_PLANK, "Planks", Skill.CONSTRUCTION),
TEAK_PLANK(ItemID.TEAK_PLANK, "Planks", Skill.CONSTRUCTION),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Planks", Skill.CONSTRUCTION),
// Logs
LOGS(ItemID.LOGS, "Logs", Skill.CONSTRUCTION, ItemID.PLANK),
OAK_LOGS(ItemID.OAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.OAK_PLANK),
TEAK_LOGS(ItemID.TEAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.TEAK_PLANK),
MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.MAHOGANY_PLANK),
/**
* Herblore Items
*/
// Grimy Herbs
GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.GUAM_LEAF),
GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, "Grimy Herbs", Skill.HERBLORE, ItemID.MARRENTILL),
GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, "Grimy Herbs", Skill.HERBLORE, ItemID.TARROMIN),
GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, "Grimy Herbs", Skill.HERBLORE, ItemID.HARRALANDER),
GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.RANARR_WEED),
GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, "Grimy Herbs", Skill.HERBLORE, ItemID.TOADFLAX),
GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.IRIT_LEAF),
GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, "Grimy Herbs", Skill.HERBLORE, ItemID.AVANTOE),
GRIMY_KWUARM(ItemID.GRIMY_KWUARM, "Grimy Herbs", Skill.HERBLORE, ItemID.KWUARM),
GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, "Grimy Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON),
GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, "Grimy Herbs", Skill.HERBLORE, ItemID.CADANTINE),
GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, "Grimy Herbs", Skill.HERBLORE, ItemID.LANTADYME),
GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.DWARF_WEED),
GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, "Grimy Herbs", Skill.HERBLORE, ItemID.TORSTOL),
// Clean Herbs
GUAM_LEAF(ItemID.GUAM_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.GUAM_POTION_UNF),
MARRENTILL(ItemID.MARRENTILL, "Cleaned Herbs", Skill.HERBLORE, ItemID.MARRENTILL_POTION_UNF),
TARROMIN(ItemID.TARROMIN, "Cleaned Herbs", Skill.HERBLORE, ItemID.TARROMIN_POTION_UNF),
HARRALANDER(ItemID.HARRALANDER, "Cleaned Herbs", Skill.HERBLORE, ItemID.HARRALANDER_POTION_UNF),
RANARR_WEED(ItemID.RANARR_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.RANARR_POTION_UNF),
TOADFLAX(ItemID.TOADFLAX, "Cleaned Herbs", Skill.HERBLORE, ItemID.TOADFLAX_POTION_UNF),
IRIT_LEAF(ItemID.IRIT_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.IRIT_POTION_UNF),
AVANTOE(ItemID.AVANTOE, "Cleaned Herbs", Skill.HERBLORE, ItemID.AVANTOE_POTION_UNF),
KWUARM(ItemID.KWUARM, "Cleaned Herbs", Skill.HERBLORE, ItemID.KWUARM_POTION_UNF),
SNAPDRAGON(ItemID.SNAPDRAGON, "Cleaned Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON_POTION_UNF),
CADANTINE(ItemID.CADANTINE, "Cleaned Herbs", Skill.HERBLORE, ItemID.CADANTINE_POTION_UNF),
LANTADYME(ItemID.LANTADYME, "Cleaned Herbs", Skill.HERBLORE, ItemID.LANTADYME_POTION_UNF),
DWARF_WEED(ItemID.DWARF_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.DWARF_WEED_POTION_UNF),
TORSTOL(ItemID.TORSTOL, "Cleaned Herbs", Skill.HERBLORE, ItemID.TORSTOL_POTION_UNF),
// Unfinished Potions
GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
/**
* Prayer Items
*/
// Bones
BONES(ItemID.BONES, "Bones", Skill.PRAYER),
WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER),
BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER),
MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER),
BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER),
JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER),
BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER),
ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER),
WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER),
DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER),
FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER),
RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER),
OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER),
// Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, true),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, true),
RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, true),
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, true),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, true),
// Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, true),
/**
* Cooking Items
*/
RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING),
RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING),
RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING),
RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING),
RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING),
RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING),
RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING),
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING),
RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING),
RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING),
RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING),
RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING),
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING),
GRAPES(ItemID.GRAPES, "Other", Skill.COOKING),
/**
* Crafting Items
*/
WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING),
FLAX(ItemID.FLAX, "Misc", Skill.CRAFTING),
MOLTEN_GLASS(ItemID.MOLTEN_GLASS, "Misc", Skill.CRAFTING),
BATTLESTAFF(ItemID.BATTLESTAFF, "Misc", Skill.CRAFTING),
// D'hide/Dragon Leather
GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.GREEN_DRAGON_LEATHER),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLUE_DRAGON_LEATHER),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.RED_DRAGON_LEATHER),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLACK_DRAGON_LEATHER),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
// Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, ItemID.OPAL),
UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, ItemID.JADE),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, ItemID.RED_TOPAZ),
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, ItemID.SAPPHIRE),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, ItemID.EMERALD),
UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, ItemID.RUBY),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, ItemID.DIAMOND),
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, ItemID.DRAGONSTONE),
UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, ItemID.ONYX),
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, ItemID.ZENYTE),
// Cut Gems
OPAL(ItemID.OPAL, "Gems", Skill.CRAFTING),
JADE(ItemID.JADE, "Gems", Skill.CRAFTING),
RED_TOPAZ(ItemID.RED_TOPAZ, "Gems", Skill.CRAFTING),
SAPPHIRE(ItemID.SAPPHIRE, "Gems", Skill.CRAFTING),
EMERALD(ItemID.EMERALD, "Gems", Skill.CRAFTING),
RUBY(ItemID.RUBY, "Gems", Skill.CRAFTING),
DIAMOND(ItemID.DIAMOND, "Gems", Skill.CRAFTING),
DRAGONSTONE(ItemID.DRAGONSTONE, "Gems", Skill.CRAFTING),
ONYX(ItemID.ONYX, "Gems", Skill.CRAFTING),
ZENYTE(ItemID.ZENYTE, "Gems", Skill.CRAFTING),
/**
* Smithing Items
*/
// Ores
IRON_ORE(ItemID.IRON_ORE, "Ore", Skill.SMITHING),
SILVER_ORE(ItemID.SILVER_ORE, "Ore", Skill.SMITHING),
GOLD_ORE(ItemID.GOLD_ORE, "Ore", Skill.SMITHING),
MITHRIL_ORE(ItemID.MITHRIL_ORE, "Ore", Skill.SMITHING),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Ore", Skill.SMITHING),
RUNITE_ORE(ItemID.RUNITE_ORE, "Ore", Skill.SMITHING),
// Bars
BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING),
IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING),
STEEL_BAR(ItemID.STEEL_BAR, "Bars", Skill.SMITHING),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING),
RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING),
/**
* Farming Items
*/
// Seeds
ACORN(ItemID.ACORN, "Seeds", Skill.FARMING),
WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING),
MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING),
YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING),
MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING),
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING),
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING),
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING),
TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING),
SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING),
// Saplings
OAK_SAPLING(ItemID.OAK_SAPLING, "Saplings", Skill.FARMING, ItemID.ACORN),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Saplings", Skill.FARMING, ItemID.WILLOW_SEED),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.MAPLE_SEED),
YEW_SAPLING(ItemID.YEW_SAPLING, "Saplings", Skill.FARMING, ItemID.YEW_SEED),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Saplings", Skill.FARMING, ItemID.MAGIC_SEED),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.APPLE_TREE_SEED),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Saplings", Skill.FARMING, ItemID.BANANA_TREE_SEED),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Saplings", Skill.FARMING, ItemID.ORANGE_TREE_SEED),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Saplings", Skill.FARMING, ItemID.CURRY_TREE_SEED),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.PINEAPPLE_SEED),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Saplings", Skill.FARMING, ItemID.PAPAYA_TREE_SEED),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Saplings", Skill.FARMING, ItemID.PALM_TREE_SEED),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Saplings", Skill.FARMING, ItemID.CALQUAT_TREE_SEED),
TEAK_SAPLING(ItemID.TEAK_SAPLING, "Saplings", Skill.FARMING, ItemID.TEAK_SEED),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Saplings", Skill.FARMING, ItemID.MAHOGANY_SEED),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Saplings", Skill.FARMING, ItemID.SPIRIT_SEED),
;
@Getter
private final int itemID;
@Getter
private final String category;
@Getter
private final Skill skill;
/**
* Should be operated on and then treated like this item or does nothing if null.
* Used mostly for things like herblore where you want Grimy, Clean, and UNF to count for creating potions.
* To do this GRIMY links to CLEAN which links to UNFINISHED which links to null
*/
@Getter
private final int linkedItemId;
@Getter
private boolean ignoreBonus;
@Getter
private ItemDefinition definition;
CriticalItem(int itemID, String category, Skill skill, int linkedItem)
{
this.itemID = itemID;
this.category = category;
this.skill = skill;
this.linkedItemId = linkedItem;
this.definition = null;
this.ignoreBonus = false;
}
CriticalItem(int itemID, String category, Skill skill)
{
this(itemID, category, skill, -1);
}
CriticalItem(int itemID, String category, Skill skill, boolean ignoreBonusXp)
{
this(itemID, category, skill, -1);
this.ignoreBonus = ignoreBonusXp;
}
// Builds a Map to reduce looping frequency
private static Map<Skill, List<CriticalItem>> buildSkillItemMap()
{
Map<Skill, List<CriticalItem>> map = new HashMap<>();
for (CriticalItem item : values())
{
map.computeIfAbsent(item.getSkill(), e -> new ArrayList<>()).add(item);
}
return map;
}
private static final Map<Skill, List<CriticalItem>> bySkillName = buildSkillItemMap();
public static List<CriticalItem> getBySkillName(Skill skill)
{
return bySkillName.get(skill);
}
// Builds a Map to reduce looping frequency
private static Map<Skill, Set<String>> buildSkillCategoryMap()
{
Map<Skill, Set<String>> map = new HashMap<>();
for (CriticalItem item : values())
{
map.computeIfAbsent(item.getSkill(), k -> new HashSet<>()).add(item.category);
}
return map;
}
private static final Map<Skill, Set<String>> bySkillCategory = buildSkillCategoryMap();
public static Set<String> getSkillCategories(Skill skill)
{
return bySkillCategory.get(skill);
}
// Builds a Map to reduce looping frequency
private static Map<String, List<CriticalItem>> buildItemSkillCategoryMap()
{
Map<String, List<CriticalItem>> map = new HashMap<>();
for (CriticalItem item : values())
{
String key = item.getCategory() + item.skill.getName();
map.computeIfAbsent(key, e -> new ArrayList<>()).add(item);
}
return map;
}
private static final Map<String, List<CriticalItem>> itemsBySkillCategory = buildItemSkillCategoryMap();
public static List<CriticalItem> getItemsForSkillCategories(Skill skill, String category)
{
return itemsBySkillCategory.get(category + skill.getName());
}
// Builds a Map to reduce looping frequency
private static Map<Integer, CriticalItem> buildItemsByIdMap()
{
Map<Integer, CriticalItem> map = new HashMap<>();
for (CriticalItem item : values())
{
map.put(item.getItemID(), item);
}
return map;
}
private static final Map<Integer, CriticalItem> itemsById = buildItemsByIdMap();
public static CriticalItem getByItemId(int id)
{
return itemsById.get(id);
}
/**
* Attaches the Item Composition to each Critical Item on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (CriticalItem i : values())
{
i.definition = m.getItemDefinition(i.getItemID());
}
}
@Override
public String toString()
{
return "CriticalItem=(name=" + this.name() + ",id=" + this.itemID + ",category=" + this.category + ")";
}
}

View File

@@ -24,17 +24,19 @@
*/ */
package net.runelite.client.plugins.skillcalculator.banked.beans; package net.runelite.client.plugins.skillcalculator.banked.beans;
import com.google.common.collect.ImmutableMultimap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.stream.Collectors;
import lombok.AccessLevel; import javax.annotation.Nullable;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID; import net.runelite.api.ItemID;
import net.runelite.api.Skill; import net.runelite.api.Skill;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; import net.runelite.client.game.ItemManager;
@Getter(AccessLevel.PUBLIC) @Getter
public enum Activity public enum Activity
{ {
/** /**
@@ -42,372 +44,679 @@ public enum Activity
*/ */
// Creating Potions // Creating Potions
// Guam // Guam
GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.GUAM_LEAF, ActivitySecondaries.UNFINISHED_POTION), GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0,
GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30, CriticalItem.GUAM_LEAF, ActivitySecondaries.SWAMP_TAR, true), CriticalItem.GUAM_LEAF, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.GUAM_POTION_UNF, 1)),
GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30,
CriticalItem.GUAM_LEAF, Secondaries.SWAMP_TAR, new ItemStack(ItemID.GUAM_TAR, 15)),
ATTACK_POTION(ItemID.ATTACK_POTION4, "Attack Potion", Skill.HERBLORE, 3, 25, CriticalItem.GUAM_LEAF_POTION_UNF, ActivitySecondaries.ATTACK_POTION), ATTACK_POTION(ItemID.ATTACK_POTION3, "Attack potion", Skill.HERBLORE, 3, 25,
CriticalItem.GUAM_LEAF_POTION_UNF, Secondaries.ATTACK_POTION, new ItemStack(ItemID.ATTACK_POTION3, 1)),
// Marrentil // Marrentil
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.MARRENTILL, ActivitySecondaries.UNFINISHED_POTION), MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5, CriticalItem.MARRENTILL, ActivitySecondaries.SWAMP_TAR, true), CriticalItem.MARRENTILL, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.MARRENTILL_POTION_UNF, 1)),
MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5,
CriticalItem.MARRENTILL, Secondaries.SWAMP_TAR, new ItemStack(ItemID.MARRENTILL_TAR, 15)),
ANTIPOISON(ItemID.ANTIPOISON4, "Antipoison", Skill.HERBLORE, 5, 37.5, CriticalItem.MARRENTILL_POTION_UNF, ActivitySecondaries.ANTIPOISON), ANTIPOISON(ItemID.ANTIPOISON3, "Antipoison", Skill.HERBLORE, 5, 37.5,
CriticalItem.MARRENTILL_POTION_UNF, Secondaries.ANTIPOISON, new ItemStack(ItemID.ANTIPOISON3, 1)),
// Tarromin // Tarromin
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.TARROMIN, ActivitySecondaries.UNFINISHED_POTION), TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55, CriticalItem.TARROMIN, ActivitySecondaries.SWAMP_TAR, true), CriticalItem.TARROMIN, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TARROMIN_POTION_UNF, 1)),
TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55,
CriticalItem.TARROMIN, Secondaries.SWAMP_TAR, new ItemStack(ItemID.TARROMIN_TAR, 15)),
STRENGTH_POTION(ItemID.STRENGTH_POTION4, "Strength potion", Skill.HERBLORE, 12, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.STRENGTH_POTION), STRENGTH_POTION(ItemID.STRENGTH_POTION3, "Strength potion", Skill.HERBLORE, 12, 50,
SERUM_207(ItemID.SERUM_207_4, "Serum 207", Skill.HERBLORE, 15, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.SERUM_207), CriticalItem.TARROMIN_POTION_UNF, Secondaries.STRENGTH_POTION, new ItemStack(ItemID.STRENGTH_POTION3, 1)),
SERUM_207(ItemID.SERUM_207_3, "Serum 207", Skill.HERBLORE, 15, 50,
CriticalItem.TARROMIN_POTION_UNF, Secondaries.SERUM_207, new ItemStack(ItemID.SERUM_207_3, 1)),
// Harralander // Harralander
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.HARRALANDER, ActivitySecondaries.UNFINISHED_POTION), HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5, CriticalItem.HARRALANDER, ActivitySecondaries.SWAMP_TAR, true), CriticalItem.HARRALANDER, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.HARRALANDER_POTION_UNF, 1)),
HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5,
CriticalItem.HARRALANDER, Secondaries.SWAMP_TAR, new ItemStack(ItemID.HARRALANDER_TAR, 15)),
COMPOST_POTION(ItemID.COMPOST_POTION4, "Compost potion", Skill.HERBLORE, 21, 60, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMPOST_POTION), COMPOST_POTION(ItemID.COMPOST_POTION3, "Compost potion", Skill.HERBLORE, 21, 60,
RESTORE_POTION(ItemID.RESTORE_POTION4, "Restore potion", Skill.HERBLORE, 22, 62.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.RESTORE_POTION), CriticalItem.HARRALANDER_POTION_UNF, Secondaries.COMPOST_POTION, new ItemStack(ItemID.COMPOST_POTION3, 1)),
ENERGY_POTION(ItemID.ENERGY_POTION4, "Energy potion", Skill.HERBLORE, 26, 67.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.ENERGY_POTION), RESTORE_POTION(ItemID.RESTORE_POTION3, "Restore potion", Skill.HERBLORE, 22, 62.5,
COMBAT_POTION(ItemID.COMBAT_POTION4, "Combat potion", Skill.HERBLORE, 36, 84, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMBAT_POTION), CriticalItem.HARRALANDER_POTION_UNF, Secondaries.RESTORE_POTION, new ItemStack(ItemID.RESTORE_POTION3, 1)),
ENERGY_POTION(ItemID.ENERGY_POTION3, "Energy potion", Skill.HERBLORE, 26, 67.5,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.ENERGY_POTION, new ItemStack(ItemID.ENERGY_POTION3, 1)),
COMBAT_POTION(ItemID.COMBAT_POTION3, "Combat potion", Skill.HERBLORE, 36, 84,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.COMBAT_POTION, new ItemStack(ItemID.COMBAT_POTION3, 1)),
// Ranarr Weed // Ranarr Weed
DEFENCE_POTION(ItemID.DEFENCE_POTION4, "Defence potion", Skill.HERBLORE, 30, 75, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.DEFENCE_POTION), RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 30, 0,
PRAYER_POTION(ItemID.PRAYER_POTION4, "Prayer potion", Skill.HERBLORE, 38, 87.5, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.PRAYER_POTION), CriticalItem.RANARR_WEED, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.RANARR_POTION_UNF, 1)),
DEFENCE_POTION(ItemID.DEFENCE_POTION3, "Defence potion", Skill.HERBLORE, 30, 75,
CriticalItem.RANARR_POTION_UNF, Secondaries.DEFENCE_POTION, new ItemStack(ItemID.DEFENCE_POTION3, 1)),
PRAYER_POTION(ItemID.PRAYER_POTION3, "Prayer potion", Skill.HERBLORE, 38, 87.5,
CriticalItem.RANARR_POTION_UNF, Secondaries.PRAYER_POTION, new ItemStack(ItemID.PRAYER_POTION3, 1)),
// Toadflax // Toadflax
AGILITY_POTION(ItemID.AGILITY_POTION4, "Agility potion", Skill.HERBLORE, 34, 80, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.AGILITY_POTION), TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 34, 0,
SARADOMIN_BREW(ItemID.SARADOMIN_BREW4, "Saradomin brew", Skill.HERBLORE, 81, 180, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.SARADOMIN_BREW), CriticalItem.TOADFLAX, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TOADFLAX_POTION_UNF, 1)),
AGILITY_POTION(ItemID.AGILITY_POTION3, "Agility potion", Skill.HERBLORE, 34, 80,
CriticalItem.TOADFLAX_POTION_UNF, Secondaries.AGILITY_POTION, new ItemStack(ItemID.AGILITY_POTION3, 1)),
SARADOMIN_BREW(ItemID.SARADOMIN_BREW3, "Saradomin brew", Skill.HERBLORE, 81, 180,
CriticalItem.TOADFLAX_POTION_UNF, Secondaries.SARADOMIN_BREW, new ItemStack(ItemID.SARADOMIN_BREW3, 1)),
// Irit // Irit
SUPER_ATTACK(ItemID.SUPER_ATTACK4, "Super attack", Skill.HERBLORE, 45, 100, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPER_ATTACK), IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 45, 0,
SUPERANTIPOISON(ItemID.SUPERANTIPOISON4, "Superantipoison", Skill.HERBLORE, 48, 106.3, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPERANTIPOISON), CriticalItem.IRIT_LEAF, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.IRIT_POTION_UNF, 1)),
SUPER_ATTACK(ItemID.SUPER_ATTACK3, "Super attack", Skill.HERBLORE, 45, 100,
CriticalItem.IRIT_POTION_UNF, Secondaries.SUPER_ATTACK, new ItemStack(ItemID.SUPER_ATTACK3, 1)),
SUPERANTIPOISON(ItemID.SUPERANTIPOISON3, "Superantipoison", Skill.HERBLORE, 48, 106.3,
CriticalItem.IRIT_POTION_UNF, Secondaries.SUPERANTIPOISON, new ItemStack(ItemID.SUPERANTIPOISON3, 1)),
// Avantoe // Avantoe
FISHING_POTION(ItemID.FISHING_POTION4, "Fishing potion", Skill.HERBLORE, 50, 112.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.FISHING_POTION), AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 50, 0,
SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.SUPER_ENERGY_POTION), CriticalItem.AVANTOE, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.AVANTOE_POTION_UNF, 1)),
HUNTER_POTION(ItemID.HUNTER_POTION4, "Hunter potion", Skill.HERBLORE, 53, 120, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.HUNTER_POTION), FISHING_POTION(ItemID.FISHING_POTION3, "Fishing potion", Skill.HERBLORE, 50, 112.5,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.FISHING_POTION, new ItemStack(ItemID.FISHING_POTION3, 1)),
SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.SUPER_ENERGY_POTION, new ItemStack(ItemID.SUPER_ENERGY3_20549, 1)),
HUNTER_POTION(ItemID.HUNTER_POTION3, "Hunter potion", Skill.HERBLORE, 53, 120,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.HUNTER_POTION, new ItemStack(ItemID.HUNTER_POTION3, 1)),
// Kwuarm // Kwuarm
SUPER_STRENGTH(ItemID.SUPER_STRENGTH4, "Super strength", Skill.HERBLORE, 55, 125, CriticalItem.KWUARM_POTION_UNF, ActivitySecondaries.SUPER_STRENGTH), KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 55, 0,
CriticalItem.KWUARM, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.KWUARM_POTION_UNF, 1)),
SUPER_STRENGTH(ItemID.SUPER_STRENGTH3, "Super strength", Skill.HERBLORE, 55, 125,
CriticalItem.KWUARM_POTION_UNF, Secondaries.SUPER_STRENGTH, new ItemStack(ItemID.SUPER_STRENGTH3, 1)),
// Snapdragon // Snapdragon
SUPER_RESTORE(ItemID.SUPER_RESTORE4, "Super restore", Skill.HERBLORE, 63, 142.5, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SUPER_RESTORE), SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 63, 0,
SANFEW_SERUM(ItemID.SANFEW_SERUM4, "Sanfew serum", Skill.HERBLORE, 65, 160, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SANFEW_SERUM), CriticalItem.SNAPDRAGON, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.SNAPDRAGON_POTION_UNF, 1)),
SUPER_RESTORE(ItemID.SUPER_RESTORE3, "Super restore", Skill.HERBLORE, 63, 142.5,
CriticalItem.SNAPDRAGON_POTION_UNF, Secondaries.SUPER_RESTORE, new ItemStack(ItemID.SUPER_RESTORE3, 1)),
SANFEW_SERUM(ItemID.SANFEW_SERUM3, "Sanfew serum", Skill.HERBLORE, 65, 160,
CriticalItem.SNAPDRAGON_POTION_UNF, Secondaries.SANFEW_SERUM, new ItemStack(ItemID.SANFEW_SERUM3, 1)),
// Cadantine // Cadantine
SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE4, "Super defence", Skill.HERBLORE, 66, 150, CriticalItem.CADANTINE_POTION_UNF, ActivitySecondaries.SUPER_DEFENCE_POTION), CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 66, 0,
CriticalItem.CADANTINE, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.CADANTINE_POTION_UNF, 1)),
SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE3, "Super defence", Skill.HERBLORE, 66, 150,
CriticalItem.CADANTINE_POTION_UNF, Secondaries.SUPER_DEFENCE_POTION, new ItemStack(ItemID.SUPER_DEFENCE3, 1)),
// Lantadyme // Lantadyme
ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION4, "Anti-fire potion", Skill.HERBLORE, 69, 157.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.ANTIFIRE_POTION), LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 69, 0,
MAGIC_POTION(ItemID.MAGIC_POTION4, "Magic potion", Skill.HERBLORE, 76, 172.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.MAGIC_POTION), CriticalItem.LANTADYME, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.LANTADYME_POTION_UNF, 1)),
ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION3, "Anti-fire potion", Skill.HERBLORE, 69, 157.5,
CriticalItem.LANTADYME_POTION_UNF, Secondaries.ANTIFIRE_POTION, new ItemStack(ItemID.ANTIFIRE_POTION3, 1)),
MAGIC_POTION(ItemID.MAGIC_POTION3, "Magic potion", Skill.HERBLORE, 76, 172.5,
CriticalItem.LANTADYME_POTION_UNF, Secondaries.MAGIC_POTION, new ItemStack(ItemID.MAGIC_POTION3, 1)),
// Dwarf Weed // Dwarf Weed
RANGING_POTION(ItemID.RANGING_POTION4, "Ranging potion", Skill.HERBLORE, 72, 162.5, CriticalItem.DWARF_WEED_POTION_UNF, ActivitySecondaries.RANGING_POTION), DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 72, 0,
CriticalItem.DWARF_WEED, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.DWARF_WEED_POTION_UNF, 1)),
RANGING_POTION(ItemID.RANGING_POTION3, "Ranging potion", Skill.HERBLORE, 72, 162.5,
CriticalItem.DWARF_WEED_POTION_UNF, Secondaries.RANGING_POTION, new ItemStack(ItemID.RANGING_POTION3, 1)),
// Torstol // Torstol
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 78, 0, CriticalItem.TORSTOL, ActivitySecondaries.UNFINISHED_POTION), TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 78, 0,
SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150, CriticalItem.TORSTOL, ActivitySecondaries.SUPER_COMBAT_POTION, true), CriticalItem.TORSTOL, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TORSTOL_POTION_UNF, 1)),
ANTIVENOM_PLUS(ItemID.ANTIVENOM4_12913, "Anti-venom+", Skill.HERBLORE, 94, 125, CriticalItem.TORSTOL, ActivitySecondaries.ANTIVENOM_PLUS, true), SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150,
CriticalItem.TORSTOL, Secondaries.SUPER_COMBAT_POTION, new ItemStack(ItemID.SUPER_COMBAT_POTION4, 1)),
ANTIVENOM_PLUS(ItemID.ANTIVENOM3_12915, "Anti-venom+", Skill.HERBLORE, 94, 125,
CriticalItem.TORSTOL, Secondaries.ANTIVENOM_PLUS, new ItemStack(ItemID.ANTIVENOM3_12915, 1)),
ZAMORAK_BREW(ItemID.ZAMORAK_BREW4, "Zamorak brew", Skill.HERBLORE, 78, 175, CriticalItem.TORSTOL_POTION_UNF, ActivitySecondaries.ZAMORAK_BREW), ZAMORAK_BREW(ItemID.ZAMORAK_BREW3, "Zamorak brew", Skill.HERBLORE, 78, 175,
CriticalItem.TORSTOL_POTION_UNF, Secondaries.ZAMORAK_BREW, new ItemStack(ItemID.ZAMORAK_BREW3, 1)),
// Cleaning Grimy Herbs // Cleaning Grimy Herbs
CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5, CriticalItem.GRIMY_GUAM_LEAF), CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5,
CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8, CriticalItem.GRIMY_MARRENTILL), CriticalItem.GRIMY_GUAM_LEAF, null, new ItemStack(ItemID.GUAM_LEAF, 1)),
CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5, CriticalItem.GRIMY_TARROMIN), CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8,
CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3, CriticalItem.GRIMY_HARRALANDER), CriticalItem.GRIMY_MARRENTILL, null, new ItemStack(ItemID.MARRENTILL, 1)),
CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5, CriticalItem.GRIMY_RANARR_WEED), CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5,
CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8, CriticalItem.GRIMY_TOADFLAX), CriticalItem.GRIMY_TARROMIN, null, new ItemStack(ItemID.TARROMIN, 1)),
CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8, CriticalItem.GRIMY_IRIT_LEAF), CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3,
CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10, CriticalItem.GRIMY_AVANTOE), CriticalItem.GRIMY_HARRALANDER, null, new ItemStack(ItemID.HARRALANDER, 1)),
CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3, CriticalItem.GRIMY_KWUARM), CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5,
CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8, CriticalItem.GRIMY_SNAPDRAGON), CriticalItem.GRIMY_RANARR_WEED, null, new ItemStack(ItemID.RANARR_WEED, 1)),
CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5, CriticalItem.GRIMY_CADANTINE), CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8,
CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1, CriticalItem.GRIMY_LANTADYME), CriticalItem.GRIMY_TOADFLAX, null, new ItemStack(ItemID.TOADFLAX, 1)),
CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8, CriticalItem.GRIMY_DWARF_WEED), CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8,
CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15, CriticalItem.GRIMY_TORSTOL), CriticalItem.GRIMY_IRIT_LEAF, null, new ItemStack(ItemID.IRIT_LEAF, 1)),
CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10,
CriticalItem.GRIMY_AVANTOE, null, new ItemStack(ItemID.AVANTOE, 1)),
CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3,
CriticalItem.GRIMY_KWUARM, null, new ItemStack(ItemID.KWUARM, 1)),
CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8,
CriticalItem.GRIMY_SNAPDRAGON, null, new ItemStack(ItemID.SNAPDRAGON, 1)),
CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5,
CriticalItem.GRIMY_CADANTINE, null, new ItemStack(ItemID.CADANTINE, 1)),
CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1,
CriticalItem.GRIMY_LANTADYME, null, new ItemStack(ItemID.LANTADYME, 1)),
CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8,
CriticalItem.GRIMY_DWARF_WEED, null, new ItemStack(ItemID.DWARF_WEED, 1)),
CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15,
CriticalItem.GRIMY_TORSTOL, null, new ItemStack(ItemID.TORSTOL, 1)),
/** /**
* Construction Options * Construction Options
*/ */
PLANKS(ItemID.PLANK, "Normal Plank Products", Skill.CONSTRUCTION, 1, 29, CriticalItem.PLANK), PLANK(ItemID.PLANK, "Regular Plank", Skill.CONSTRUCTION, 1, 0,
OAK_PLANKS(ItemID.OAK_PLANK, "Normal Oak Products", Skill.CONSTRUCTION, 1, 60, CriticalItem.OAK_PLANK), CriticalItem.LOGS, Secondaries.COINS_100, new ItemStack(ItemID.PLANK, 1)),
TEAK_PLANKS(ItemID.TEAK_PLANK, "Normal Teak Products", Skill.CONSTRUCTION, 1, 90, CriticalItem.TEAK_PLANK), PLANKS(ItemID.PLANK, "Regular plank products", Skill.CONSTRUCTION, 1, 29,
MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical Cape Rakes", Skill.CONSTRUCTION, 1, 123.33, CriticalItem.TEAK_PLANK), CriticalItem.PLANK, null, null),
MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Normal Mahogany Products", Skill.CONSTRUCTION, 1, 140, CriticalItem.MAHOGANY_PLANK),
OAK_PLANK(ItemID.OAK_PLANK, "Oak Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.OAK_LOGS, Secondaries.COINS_250, new ItemStack(ItemID.OAK_PLANK, 1)),
OAK_PLANKS(ItemID.OAK_PLANK, "Oak products", Skill.CONSTRUCTION, 1, 60,
CriticalItem.OAK_PLANK, null, null),
TEAK_PLANK(ItemID.TEAK_PLANK, "Teak Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.TEAK_LOGS, Secondaries.COINS_500, new ItemStack(ItemID.TEAK_PLANK, 1)),
TEAK_PLANKS(ItemID.TEAK_PLANK, "Teak products", Skill.CONSTRUCTION, 1, 90,
CriticalItem.TEAK_PLANK, null, null),
MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical cape rakes", Skill.CONSTRUCTION, 1, 123.33,
CriticalItem.TEAK_PLANK, null, null),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Mahogany Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.MAHOGANY_LOGS, Secondaries.COINS_1500, new ItemStack(ItemID.MAHOGANY_PLANK, 1)),
MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Mahogany products", Skill.CONSTRUCTION, 1, 140,
CriticalItem.MAHOGANY_PLANK, null, null),
/** /**
* Prayer Options * Prayer Options
*/ */
BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BONES), BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5,
WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.WOLF_BONES), CriticalItem.BONES, null, null),
BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BURNT_BONES), WOLF_BONES(ItemID.WOLF_BONES, "Wolf bones", Skill.PRAYER, 1, 4.5,
MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER, 1, 5.0, CriticalItem.MONKEY_BONES), CriticalItem.WOLF_BONES, null, null),
BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER, 1, 5.3, CriticalItem.BAT_BONES), BURNT_BONES(ItemID.BURNT_BONES, "Burnt bones", Skill.PRAYER, 1, 4.5,
JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.JOGRE_BONES), CriticalItem.BURNT_BONES, null, null),
BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.BIG_BONES), MONKEY_BONES(ItemID.MONKEY_BONES, "Monkey bones", Skill.PRAYER, 1, 5.0,
ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER, 1, 22.5, CriticalItem.ZOGRE_BONES), CriticalItem.MONKEY_BONES, null, null),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER, 1, 25.0, CriticalItem.SHAIKAHAN_BONES), BAT_BONES(ItemID.BAT_BONES, "Bat bones", Skill.PRAYER, 1, 5.3,
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER, 1, 30.0, CriticalItem.BABYDRAGON_BONES), CriticalItem.BAT_BONES, null, null),
WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.WYVERN_BONES), JOGRE_BONES(ItemID.JOGRE_BONES, "Jogre bones", Skill.PRAYER, 1, 15.0,
DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.DRAGON_BONES), CriticalItem.JOGRE_BONES, null, null),
FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER, 1, 84.0, CriticalItem.FAYRG_BONES), BIG_BONES(ItemID.BIG_BONES, "Big bones", Skill.PRAYER, 1, 15.0,
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 85.0, CriticalItem.LAVA_DRAGON_BONES), CriticalItem.BIG_BONES, null, null),
RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER, 1, 96.0, CriticalItem.RAURG_BONES), ZOGRE_BONES(ItemID.ZOGRE_BONES, "Zogre bones", Skill.PRAYER, 1, 22.5,
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER, 1, 125.0, CriticalItem.DAGANNOTH_BONES), CriticalItem.ZOGRE_BONES, null, null),
OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER, 1, 140.0, CriticalItem.OURG_BONES), SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Shaikahan bones", Skill.PRAYER, 1, 25.0,
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 150.0, CriticalItem.SUPERIOR_DRAGON_BONES), CriticalItem.SHAIKAHAN_BONES, null, null),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Babydragon bones", Skill.PRAYER, 1, 30.0,
CriticalItem.BABYDRAGON_BONES, null, null),
WYVERN_BONES(ItemID.WYVERN_BONES, "Wyvern bones", Skill.PRAYER, 1, 72.0,
CriticalItem.WYVERN_BONES, null, null),
DRAGON_BONES(ItemID.DRAGON_BONES, "Dragon bones", Skill.PRAYER, 1, 72.0,
CriticalItem.DRAGON_BONES, null, null),
FAYRG_BONES(ItemID.FAYRG_BONES, "Fayrg bones", Skill.PRAYER, 1, 84.0,
CriticalItem.FAYRG_BONES, null, null),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Lava dragon bones", Skill.PRAYER, 1, 85.0,
CriticalItem.LAVA_DRAGON_BONES, null, null),
RAURG_BONES(ItemID.RAURG_BONES, "Raurg bones", Skill.PRAYER, 1, 96.0,
CriticalItem.RAURG_BONES, null, null),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Dagannoth bones", Skill.PRAYER, 1, 125.0,
CriticalItem.DAGANNOTH_BONES, null, null),
OURG_BONES(ItemID.OURG_BONES, "Ourg bones", Skill.PRAYER, 1, 140.0,
CriticalItem.OURG_BONES, null, null),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Superior dragon bones", Skill.PRAYER, 1, 150.0,
CriticalItem.SUPERIOR_DRAGON_BONES, null, null),
// Shade Remains (Pyre Logs) // Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, 1, 33.0, CriticalItem.LOAR_REMAINS), LOAR_REMAINS(ItemID.LOAR_REMAINS, "Loar remains", Skill.PRAYER, 1, 33.0,
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, 1, 46.5, CriticalItem.PHRIN_REMAINS), CriticalItem.LOAR_REMAINS, null, null),
RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, 1, 59.5, CriticalItem.RIYL_REMAINS), PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Phrin remains", Skill.PRAYER, 1, 46.5,
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, 1, 82.5, CriticalItem.ASYN_REMAINS), CriticalItem.PHRIN_REMAINS, null, null),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, 1, 84.0, CriticalItem.FIYR_REMAINS), RIYL_REMAINS(ItemID.RIYL_REMAINS, "Riyl remains", Skill.PRAYER, 1, 59.5,
CriticalItem.RIYL_REMAINS, null, null),
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Asyn remains", Skill.PRAYER, 1, 82.5,
CriticalItem.ASYN_REMAINS, null, null),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Fiyre remains", Skill.PRAYER, 1, 84.0,
CriticalItem.FIYR_REMAINS, null, null),
// Ensouled Heads // Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, 1, 130.0, CriticalItem.ENSOULED_GOBLIN_HEAD), ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled goblin head", Skill.PRAYER, 1, 130.0,
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, 1, 182.0, CriticalItem.ENSOULED_MONKEY_HEAD), CriticalItem.ENSOULED_GOBLIN_HEAD, null, null),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, 1, 286.0, CriticalItem.ENSOULED_IMP_HEAD), ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled monkey head", Skill.PRAYER, 1, 182.0,
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, 1, 364.0, CriticalItem.ENSOULED_MINOTAUR_HEAD), CriticalItem.ENSOULED_MONKEY_HEAD, null, null),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, 1, 454.0, CriticalItem.ENSOULED_SCORPION_HEAD), ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled imp head", Skill.PRAYER, 1, 286.0,
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, 1, 480.0, CriticalItem.ENSOULED_BEAR_HEAD), CriticalItem.ENSOULED_IMP_HEAD, null, null),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, 1, 494.0, CriticalItem.ENSOULED_UNICORN_HEAD), ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled minotaur head", Skill.PRAYER, 1, 364.0,
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, 1, 520.0, CriticalItem.ENSOULED_DOG_HEAD), CriticalItem.ENSOULED_MINOTAUR_HEAD, null, null),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, 1, 584.0, CriticalItem.ENSOULED_CHAOS_DRUID_HEAD), ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled scorpion head", Skill.PRAYER, 1, 454.0,
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, 1, 650.0, CriticalItem.ENSOULED_GIANT_HEAD), CriticalItem.ENSOULED_SCORPION_HEAD, null, null),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, 1, 716.0, CriticalItem.ENSOULED_OGRE_HEAD), ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled bear head", Skill.PRAYER, 1, 480.0,
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, 1, 754.0, CriticalItem.ENSOULED_ELF_HEAD), CriticalItem.ENSOULED_BEAR_HEAD, null, null),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, 1, 780.0, CriticalItem.ENSOULED_TROLL_HEAD), ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled unicorn head", Skill.PRAYER, 1, 494.0,
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, 1, 832.0, CriticalItem.ENSOULED_HORROR_HEAD), CriticalItem.ENSOULED_UNICORN_HEAD, null, null),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, 1, 884.0, CriticalItem.ENSOULED_KALPHITE_HEAD), ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled dog head", Skill.PRAYER, 1, 520.0,
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, 1, 936.0, CriticalItem.ENSOULED_DAGANNOTH_HEAD), CriticalItem.ENSOULED_DOG_HEAD, null, null),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, 1, 1040.0, CriticalItem.ENSOULED_BLOODVELD_HEAD), ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled druid head", Skill.PRAYER, 1, 584.0,
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, 1, 1104.0, CriticalItem.ENSOULED_TZHAAR_HEAD), CriticalItem.ENSOULED_CHAOS_DRUID_HEAD, null, null),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, 1, 1170.0, CriticalItem.ENSOULED_DEMON_HEAD), ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled giant head", Skill.PRAYER, 1, 650.0,
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, 1, 1234.0, CriticalItem.ENSOULED_AVIANSIE_HEAD), CriticalItem.ENSOULED_GIANT_HEAD, null, null),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, 1, 1300.0, CriticalItem.ENSOULED_ABYSSAL_HEAD), ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled ogre head", Skill.PRAYER, 1, 716.0,
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, 1, 1560.0, CriticalItem.ENSOULED_DRAGON_HEAD), CriticalItem.ENSOULED_OGRE_HEAD, null, null),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled elf head", Skill.PRAYER, 1, 754.0,
CriticalItem.ENSOULED_ELF_HEAD, null, null),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled troll head", Skill.PRAYER, 1, 780.0,
CriticalItem.ENSOULED_TROLL_HEAD, null, null),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled horror head", Skill.PRAYER, 1, 832.0,
CriticalItem.ENSOULED_HORROR_HEAD, null, null),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled kalphite head", Skill.PRAYER, 1, 884.0,
CriticalItem.ENSOULED_KALPHITE_HEAD, null, null),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled dagannoth head", Skill.PRAYER, 1, 936.0,
CriticalItem.ENSOULED_DAGANNOTH_HEAD, null, null),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled bloodveld head", Skill.PRAYER, 1, 1040.0,
CriticalItem.ENSOULED_BLOODVELD_HEAD, null, null),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled tzhaar head", Skill.PRAYER, 1, 1104.0,
CriticalItem.ENSOULED_TZHAAR_HEAD, null, null),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled demon head", Skill.PRAYER, 1, 1170.0,
CriticalItem.ENSOULED_DEMON_HEAD, null, null),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled aviansie head", Skill.PRAYER, 1, 1234.0,
CriticalItem.ENSOULED_AVIANSIE_HEAD, null, null),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled abyssal head", Skill.PRAYER, 1, 1300.0,
CriticalItem.ENSOULED_ABYSSAL_HEAD, null, null),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled dragon head", Skill.PRAYER, 1, 1560.0,
CriticalItem.ENSOULED_DRAGON_HEAD, null, null),
/* /*
* Cooking Items * Cooking Items
*/ */
RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING, 5, 50.0, CriticalItem.RAW_HERRING), COOK_HERRING(ItemID.HERRING, "Herring", Skill.COOKING, 5, 50.0,
RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING, 10, 60.0, CriticalItem.RAW_MACKEREL), CriticalItem.RAW_HERRING, null, new ItemStack(ItemID.HERRING, 1)),
RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING, 15, 70.0, CriticalItem.RAW_TROUT), COOK_MACKEREL(ItemID.MACKEREL, "Mackerel", Skill.COOKING, 10, 60.0,
RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING, 18, 75.0, CriticalItem.RAW_COD), CriticalItem.RAW_MACKEREL, null, new ItemStack(ItemID.MACKEREL, 1)),
RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING, 20, 80.0, CriticalItem.RAW_PIKE), COOK_TROUT(ItemID.TROUT, "Trout", Skill.COOKING, 15, 70.0,
RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING, 25, 90.0, CriticalItem.RAW_SALMON), CriticalItem.RAW_TROUT, null, new ItemStack(ItemID.TROUT, 1)),
RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING, 30, 100.0, CriticalItem.RAW_TUNA), COOK_COD(ItemID.COD, "Cod", Skill.COOKING, 18, 75.0,
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING, 30, 190.0, CriticalItem.RAW_KARAMBWAN), CriticalItem.RAW_COD, null, new ItemStack(ItemID.COD, 1)),
RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING, 40, 120.0, CriticalItem.RAW_LOBSTER), COOK_PIKE(ItemID.PIKE, "Pike", Skill.COOKING, 20, 80.0,
RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING, 43, 130.0, CriticalItem.RAW_BASS), CriticalItem.RAW_PIKE, null, new ItemStack(ItemID.PIKE, 1)),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING, 45, 140.0, CriticalItem.RAW_SWORDFISH), COOK_SALMON(ItemID.SALMON, "Salmon", Skill.COOKING, 25, 90.0,
RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING, 62, 150.0, CriticalItem.RAW_MONKFISH), CriticalItem.RAW_SALMON, null, new ItemStack(ItemID.SALMON, 1)),
RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING, 80, 210.0, CriticalItem.RAW_SHARK), COOK_TUNA(ItemID.TUNA, "Tuna", Skill.COOKING, 30, 100.0,
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING, 82, 211.3, CriticalItem.RAW_SEA_TURTLE), CriticalItem.RAW_TUNA, null, new ItemStack(ItemID.TUNA, 1)),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING, 84, 230.0, CriticalItem.RAW_ANGLERFISH), COOK_KARAMBWAN(ItemID.COOKED_KARAMBWAN, "Cooked Karambwan", Skill.COOKING, 30, 190.0,
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING, 90, 215.0, CriticalItem.RAW_DARK_CRAB), CriticalItem.RAW_KARAMBWAN, null, new ItemStack(ItemID.COOKED_KARAMBWAN, 1)),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING, 91, 216.2, CriticalItem.RAW_MANTA_RAY), COOK_LOBSTER(ItemID.LOBSTER, "Lobster", Skill.COOKING, 40, 120.0,
CriticalItem.RAW_LOBSTER, null, new ItemStack(ItemID.LOBSTER, 1)),
COOK_BASS(ItemID.BASS, "Bass", Skill.COOKING, 43, 130.0,
CriticalItem.RAW_BASS, null, new ItemStack(ItemID.BASS, 1)),
COOK_SWORDFISH(ItemID.SWORDFISH, "Swordfish", Skill.COOKING, 45, 140.0,
CriticalItem.RAW_SWORDFISH, null, new ItemStack(ItemID.SWORDFISH, 1)),
COOK_MONKFISH(ItemID.MONKFISH, "Monkfish", Skill.COOKING, 62, 150.0,
CriticalItem.RAW_MONKFISH, null, new ItemStack(ItemID.MONKFISH, 1)),
COOK_SHARK(ItemID.SHARK, "Shark", Skill.COOKING, 80, 210.0,
CriticalItem.RAW_SHARK, null, new ItemStack(ItemID.SHARK, 1)),
COOK_SEA_TURTLE(ItemID.SEA_TURTLE, "Sea turtle", Skill.COOKING, 82, 211.3,
CriticalItem.RAW_SEA_TURTLE, null, new ItemStack(ItemID.SEA_TURTLE, 1)),
COOK_ANGLERFISH(ItemID.ANGLERFISH, "Anglerfish", Skill.COOKING, 84, 230.0,
CriticalItem.RAW_ANGLERFISH, null, new ItemStack(ItemID.ANGLERFISH, 1)),
COOK_DARK_CRAB(ItemID.DARK_CRAB, "Dark crab", Skill.COOKING, 90, 215.0,
CriticalItem.RAW_DARK_CRAB, null, new ItemStack(ItemID.DARK_CRAB, 1)),
COOK_MANTA_RAY(ItemID.MANTA_RAY, "Manta ray", Skill.COOKING, 91, 216.2,
CriticalItem.RAW_MANTA_RAY, null, new ItemStack(ItemID.MANTA_RAY, 1)),
WINE(ItemID.JUG_OF_WINE, "Other", Skill.COOKING, 35, 200, CriticalItem.GRAPES, ActivitySecondaries.JUG_OF_WATER), WINE(ItemID.JUG_OF_WINE, "Jug of wine", Skill.COOKING, 35, 200,
CriticalItem.GRAPES, Secondaries.JUG_OF_WATER, new ItemStack(ItemID.JUG_OF_WINE, 1)),
/* /*
* Crafting Items * Crafting Items
*/ */
// Spinning // Spinning
BALL_OF_WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING, 1, 2.5, CriticalItem.WOOL), BALL_OF_WOOL(ItemID.BALL_OF_WOOL, "Ball of wool", Skill.CRAFTING, 1, 2.5,
BOW_STRING(ItemID.BOW_STRING, "Misc", Skill.CRAFTING, 1, 15, CriticalItem.FLAX), CriticalItem.WOOL, null, new ItemStack(ItemID.BALL_OF_WOOL, 1)),
BOW_STRING(ItemID.BOW_STRING, "Bow string", Skill.CRAFTING, 1, 15,
CriticalItem.FLAX, null, new ItemStack(ItemID.BOW_STRING, 1)),
// Glass Blowing // Glass Blowing
BEER_GLASS(ItemID.BEER_GLASS, "Beer Glass", Skill.CRAFTING, 1, 17.5, CriticalItem.MOLTEN_GLASS), BEER_GLASS(ItemID.BEER_GLASS, "Beer glass", Skill.CRAFTING, 1, 17.5,
CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle Lantern", Skill.CRAFTING, 4, 19, CriticalItem.MOLTEN_GLASS), CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.BEER_GLASS, 1)),
OIL_LAMP(ItemID.OIL_LAMP, "Oil Lamp", Skill.CRAFTING, 12, 25, CriticalItem.MOLTEN_GLASS), CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle lantern", Skill.CRAFTING, 4, 19,
VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35, CriticalItem.MOLTEN_GLASS), CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.CANDLE_LANTERN, 1)),
EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5, CriticalItem.MOLTEN_GLASS), OIL_LAMP(ItemID.OIL_LAMP, "Oil lamp", Skill.CRAFTING, 12, 25,
UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5, CriticalItem.MOLTEN_GLASS), CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.OIL_LAMP, 1)),
LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55, CriticalItem.MOLTEN_GLASS), VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35,
LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70, CriticalItem.MOLTEN_GLASS), CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.VIAL, 1)),
EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.EMPTY_FISHBOWL, 1)),
UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.UNPOWERED_ORB, 1)),
LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.LANTERN_LENS, 1)),
LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.LIGHT_ORB, 1)),
// D'hide/Dragon Leather // D'hide/Dragon Leather
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 57, 62.0, CriticalItem.GREEN_DRAGON_LEATHER), GREEN_DRAGONHIDE(ItemID.GREEN_DRAGON_LEATHER, "Tan Green D'hide", Skill.CRAFTING, 57, 0,
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 66, 70.0, CriticalItem.BLUE_DRAGON_LEATHER), CriticalItem.GREEN_DRAGONHIDE, null, new ItemStack(ItemID.GREEN_DRAGON_LEATHER, 1)),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 73, 78.0, CriticalItem.RED_DRAGON_LEATHER), BLUE_DRAGONHIDE(ItemID.BLUE_DRAGON_LEATHER, "Tan Blue D'hide", Skill.CRAFTING, 66, 0,
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 79, 86.0, CriticalItem.BLACK_DRAGON_LEATHER), CriticalItem.BLUE_DRAGONHIDE, null, new ItemStack(ItemID.BLUE_DRAGON_LEATHER, 1)),
RED_DRAGONHIDE(ItemID.RED_DRAGON_LEATHER, "Tan Red D'hide", Skill.CRAFTING, 73, 0,
CriticalItem.RED_DRAGONHIDE, null, new ItemStack(ItemID.RED_DRAGON_LEATHER, 1)),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGON_LEATHER, "Tan Black D'hide", Skill.CRAFTING, 79, 0,
CriticalItem.BLACK_DRAGONHIDE, null, new ItemStack(ItemID.BLACK_DRAGON_LEATHER, 1)),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DHIDE_VAMB, "Green D'hide product", Skill.CRAFTING, 57, 62.0,
CriticalItem.GREEN_DRAGON_LEATHER, null, null),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DHIDE_VAMB, "Blue D'hide product", Skill.CRAFTING, 66, 70.0,
CriticalItem.BLUE_DRAGON_LEATHER, null, null),
RED_DRAGON_LEATHER(ItemID.RED_DHIDE_VAMB, "Red D'hide product", Skill.CRAFTING, 73, 78.0,
CriticalItem.RED_DRAGON_LEATHER, null, null),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DHIDE_VAMB, "Black D'hide product", Skill.CRAFTING, 79, 86.0,
CriticalItem.BLACK_DRAGON_LEATHER, null, null),
// Uncut Gems // Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, 1, 15.0, CriticalItem.UNCUT_OPAL), UNCUT_OPAL(ItemID.OPAL, "Cut opal", Skill.CRAFTING, 1, 15.0,
UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, 13, 20.0, CriticalItem.UNCUT_JADE), CriticalItem.UNCUT_OPAL, null, new ItemStack(ItemID.OPAL, 1)),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, 16, 25.0, CriticalItem.UNCUT_RED_TOPAZ), UNCUT_JADE(ItemID.JADE, "Cut jade", Skill.CRAFTING, 13, 20.0,
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, 20, 50.0, CriticalItem.UNCUT_SAPPHIRE), CriticalItem.UNCUT_JADE, null, new ItemStack(ItemID.JADE, 1)),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, 27, 67.5, CriticalItem.UNCUT_EMERALD), UNCUT_RED_TOPAZ(ItemID.RED_TOPAZ, "Cut red topaz", Skill.CRAFTING, 16, 25.0,
UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, 34, 85, CriticalItem.UNCUT_RUBY), CriticalItem.UNCUT_RED_TOPAZ, null, new ItemStack(ItemID.RED_TOPAZ, 1)),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, 43, 107.5, CriticalItem.UNCUT_DIAMOND), UNCUT_SAPPHIRE(ItemID.SAPPHIRE, "Cut sapphire", Skill.CRAFTING, 20, 50.0,
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, 55, 137.5, CriticalItem.UNCUT_DRAGONSTONE), CriticalItem.UNCUT_SAPPHIRE, null, new ItemStack(ItemID.SAPPHIRE, 1)),
UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, 67, 167.5, CriticalItem.UNCUT_ONYX), UNCUT_EMERALD(ItemID.EMERALD, "Cut emerald", Skill.CRAFTING, 27, 67.5,
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, 89, 200.0, CriticalItem.UNCUT_ZENYTE), CriticalItem.UNCUT_EMERALD, null, new ItemStack(ItemID.EMERALD, 1)),
UNCUT_RUBY(ItemID.RUBY, "Cut ruby", Skill.CRAFTING, 34, 85,
CriticalItem.UNCUT_RUBY, null, new ItemStack(ItemID.RUBY, 1)),
UNCUT_DIAMOND(ItemID.DIAMOND, "Cut diamond", Skill.CRAFTING, 43, 107.5,
CriticalItem.UNCUT_DIAMOND, null, new ItemStack(ItemID.DIAMOND, 1)),
UNCUT_DRAGONSTONE(ItemID.DRAGONSTONE, "Cut dragonstone", Skill.CRAFTING, 55, 137.5,
CriticalItem.UNCUT_DRAGONSTONE, null, new ItemStack(ItemID.DRAGONSTONE, 1)),
UNCUT_ONYX(ItemID.ONYX, "Cut onyx", Skill.CRAFTING, 67, 167.5,
CriticalItem.UNCUT_ONYX, null, new ItemStack(ItemID.ONYX, 1)),
UNCUT_ZENYTE(ItemID.ZENYTE, "Cut zenyte", Skill.CRAFTING, 89, 200.0,
CriticalItem.UNCUT_ZENYTE, null, new ItemStack(ItemID.ZENYTE, 1)),
// Silver Jewelery // Silver Jewelery
OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1, 10, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1, 10,
OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16, 35, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_RING, 1)),
OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22, 45, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16, 35,
OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27, 55, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_NECKLACE, 1)),
JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13, 32, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22, 45,
JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25, 54, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_BRACELET, 1)),
JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29, 60, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27, 55,
JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34, 70, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_AMULET, 1)),
TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16, 35, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13, 32,
TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32, 70, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_RING, 1)),
TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38, 75, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25, 54,
TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45, 80, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_NECKLACE, 1)),
JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29, 60,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_BRACELET, 1)),
JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34, 70,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_AMULET, 1)),
TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16, 35,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_RING, 1)),
TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32, 70,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_NECKLACE, 1)),
TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38, 75,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_BRACELET, 1)),
TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45, 80,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_AMULET, 1)),
// Gold Jewelery // Gold Jewelery
SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20, 40, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20, 40,
SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22, 55, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_RING, 1)),
SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23, 60, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22, 55,
SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24, 65, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_NECKLACE, 1)),
EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27, 55, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23, 60,
EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29, 60, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_BRACELET, 1)),
EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30, 65, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24, 65,
EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31, 70, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_AMULET, 1)),
RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34, 70, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27, 55,
RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40, 75, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_RING, 1)),
RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42, 80, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29, 60,
RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50, 85, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_NECKLACE, 1)),
DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43, 85, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30, 65,
DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56, 90, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_BRACELET, 1)),
DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58, 95, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31, 70,
DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70, 100, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_AMULET, 1)),
DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55, 100, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34, 70,
DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72, 105, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_RING, 1)),
DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74, 110, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40, 75,
DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80, 150, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_NECKLACE, 1)),
ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67, 115, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42, 80,
ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82, 120, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_BRACELET, 1)),
REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84, 125, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50, 85,
ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90, 165, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_AMULET, 1)),
ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89, 150, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43, 85,
ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92, 165, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_RING, 1)),
ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95, 180, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56, 90,
ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98, 200, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_NECKLACE, 1)),
DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58, 95,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_BRACELET, 1)),
DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70, 100,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_AMULET, 1)),
DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55, 100,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_RING, 1)),
DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72, 105,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGON_NECKLACE, 1)),
DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74, 110,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_BRACELET, 1)),
DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80, 150,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_AMULET, 1)),
ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67, 115,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_RING, 1)),
ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82, 120,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_NECKLACE, 1)),
REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84, 125,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.REGEN_BRACELET, 1)),
ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90, 165,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_AMULET, 1)),
ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89, 150,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_RING, 1)),
ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92, 165,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_NECKLACE, 1)),
ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95, 180,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_BRACELET, 1)),
ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98, 200,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_AMULET, 1)),
// Battle Staves // Battle Staves
WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100, CriticalItem.BATTLESTAFF, ActivitySecondaries.WATER_ORB), WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100,
EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.EARTH_ORB), CriticalItem.BATTLESTAFF, Secondaries.WATER_ORB, new ItemStack(ItemID.WATER_BATTLESTAFF, 1)),
FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125, CriticalItem.BATTLESTAFF, ActivitySecondaries.FIRE_ORB), EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5,
AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.AIR_ORB), CriticalItem.BATTLESTAFF, Secondaries.EARTH_ORB, new ItemStack(ItemID.EARTH_BATTLESTAFF, 1)),
FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125,
CriticalItem.BATTLESTAFF, Secondaries.FIRE_ORB, new ItemStack(ItemID.FIRE_BATTLESTAFF, 1)),
AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5,
CriticalItem.BATTLESTAFF, Secondaries.AIR_ORB, new ItemStack(ItemID.AIR_BATTLESTAFF, 1)),
/* /*
* Smithing Items * Smithing Items
*/ */
// Smelting ores (Furnace) // Smelting ores (Furnace)
IRON_ORE(ItemID.IRON_BAR, "Iron Bars", Skill.SMITHING, 15, 12.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE), IRON_ORE(ItemID.IRON_BAR, "Iron bar", Skill.SMITHING, 15, 12.5,
STEEL_ORE(ItemID.STEEL_BAR, "Steel Bars", Skill.SMITHING, 30, 17.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE_2), CriticalItem.IRON_ORE, Secondaries.COAL_ORE, new ItemStack(ItemID.IRON_BAR, 1)),
SILVER_ORE(ItemID.SILVER_ORE, "Bar", Skill.SMITHING, 20, 13.67, CriticalItem.SILVER_ORE), STEEL_ORE(ItemID.STEEL_BAR, "Steel bar", Skill.SMITHING, 30, 17.5,
GOLD_ORE(ItemID.GOLD_BAR, "Regular exp", Skill.SMITHING, 40, 22.5, CriticalItem.GOLD_ORE), CriticalItem.IRON_ORE, Secondaries.COAL_ORE_2, new ItemStack(ItemID.STEEL_BAR, 1)),
GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith Gauntlets", Skill.SMITHING, 40, 56.2, CriticalItem.GOLD_ORE), SILVER_ORE(ItemID.SILVER_BAR, "Silver Bar", Skill.SMITHING, 20, 13.67,
MITHRIL_ORE(ItemID.MITHRIL_ORE, "Bar", Skill.SMITHING, 50, 30, CriticalItem.MITHRIL_ORE, ActivitySecondaries.COAL_ORE_4), CriticalItem.SILVER_ORE, null, new ItemStack(ItemID.SILVER_BAR, 1)),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Bar", Skill.SMITHING, 70, 37.5, CriticalItem.ADAMANTITE_ORE, ActivitySecondaries.COAL_ORE_6), GOLD_ORE(ItemID.GOLD_BAR, "Gold bar", Skill.SMITHING, 40, 22.5,
RUNITE_ORE(ItemID.RUNITE_ORE, "Bar", Skill.SMITHING, 85, 50, CriticalItem.RUNITE_ORE, ActivitySecondaries.COAL_ORE_8), CriticalItem.GOLD_ORE, null, new ItemStack(ItemID.GOLD_BAR, 1)),
GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith gauntlets", Skill.SMITHING, 40, 56.2,
CriticalItem.GOLD_ORE, null, new ItemStack(ItemID.GOLD_BAR, 1)),
MITHRIL_ORE(ItemID.MITHRIL_BAR, "Mithril bar", Skill.SMITHING, 50, 30,
CriticalItem.MITHRIL_ORE, Secondaries.COAL_ORE_4, new ItemStack(ItemID.MITHRIL_BAR, 1)),
ADAMANTITE_ORE(ItemID.ADAMANTITE_BAR, "Adamantite bar", Skill.SMITHING, 70, 37.5,
CriticalItem.ADAMANTITE_ORE, Secondaries.COAL_ORE_6, new ItemStack(ItemID.ADAMANTITE_BAR, 1)),
RUNITE_ORE(ItemID.RUNITE_BAR, "Runite bar", Skill.SMITHING, 85, 50,
CriticalItem.RUNITE_ORE, Secondaries.COAL_ORE_8, new ItemStack(ItemID.RUNITE_BAR, 1)),
// Smelting bars (Anvil) // Smelting bars (Anvil)
BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING, 1, 12.5, CriticalItem.BRONZE_BAR), BRONZE_BAR(ItemID.BRONZE_BAR, "Bronze products", Skill.SMITHING, 1, 12.5,
IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING, 15, 25.0, CriticalItem.IRON_BAR), CriticalItem.BRONZE_BAR, null, null),
STEEL_BAR(ItemID.STEEL_BAR, "Steel Products", Skill.SMITHING, 30, 37.5, CriticalItem.STEEL_BAR), IRON_BAR(ItemID.IRON_BAR, "Iron products", Skill.SMITHING, 15, 25.0,
CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5, CriticalItem.STEEL_BAR), CriticalItem.IRON_BAR, null, null),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING, 50, 50.0, CriticalItem.MITHRIL_BAR), STEEL_BAR(ItemID.STEEL_BAR, "Steel products", Skill.SMITHING, 30, 37.5,
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING, 70, 62.5, CriticalItem.ADAMANTITE_BAR), CriticalItem.STEEL_BAR, null, null),
RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING, 85, 75.0, CriticalItem.RUNITE_BAR), CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5,
CriticalItem.STEEL_BAR, null, new ItemStack(ItemID.CANNONBALL, 4)),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Mithril products", Skill.SMITHING, 50, 50.0,
CriticalItem.MITHRIL_BAR, null, null),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Adamantite products", Skill.SMITHING, 70, 62.5,
CriticalItem.ADAMANTITE_BAR, null, null),
RUNITE_BAR(ItemID.RUNITE_BAR, "Runite products", Skill.SMITHING, 85, 75.0,
CriticalItem.RUNITE_BAR, null, null),
/** /**
* Farming Items * Farming Items
*/ */
ACORN(ItemID.ACORN, "Seeds", Skill.FARMING, 15, 481.3, CriticalItem.ACORN), ACORN(ItemID.OAK_SAPLING, "Oak sapling", Skill.FARMING, 15, 0,
WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING, 30, 1481.5, CriticalItem.WILLOW_SEED), CriticalItem.ACORN, null, new ItemStack(ItemID.OAK_SAPLING, 1)),
MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING, 45, 3448.4, CriticalItem.MAPLE_SEED), WILLOW_SEED(ItemID.WILLOW_SAPLING, "Willow sapling", Skill.FARMING, 30, 0,
YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING, 60, 7150.9, CriticalItem.YEW_SEED), CriticalItem.WILLOW_SEED, null, new ItemStack(ItemID.WILLOW_SAPLING, 1)),
MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING, 75, 13913.8, CriticalItem.MAGIC_SEED), MAPLE_SEED(ItemID.MAPLE_SAPLING, "Maple sapling", Skill.FARMING, 45, 0,
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING, 27, 1272.5, CriticalItem.APPLE_TREE_SEED), CriticalItem.MAPLE_SEED, null, new ItemStack(ItemID.MAPLE_SAPLING, 1)),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING, 33, 1841.5, CriticalItem.BANANA_TREE_SEED), YEW_SEED(ItemID.YEW_SAPLING, "Yew sapling", Skill.FARMING, 60, 0,
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING, 39, 2586.7, CriticalItem.ORANGE_TREE_SEED), CriticalItem.YEW_SEED, null, new ItemStack(ItemID.YEW_SAPLING, 1)),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING, 42, 3036.9, CriticalItem.CURRY_TREE_SEED), MAGIC_SEED(ItemID.MAGIC_SAPLING, "Magic sapling", Skill.FARMING, 75, 0,
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING, 51, 4791.7, CriticalItem.PINEAPPLE_SEED), CriticalItem.MAGIC_SEED, null, new ItemStack(ItemID.MAGIC_SAPLING, 1)),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING, 57, 6380.4, CriticalItem.PAPAYA_TREE_SEED), APPLE_TREE_SEED(ItemID.APPLE_SAPLING, "Apple sapling", Skill.FARMING, 27, 0,
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING, 68, 10509.6, CriticalItem.PALM_TREE_SEED), CriticalItem.APPLE_TREE_SEED, null, new ItemStack(ItemID.APPLE_SAPLING, 1)),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING, 72, 12516.5, CriticalItem.CALQUAT_TREE_SEED), BANANA_TREE_SEED(ItemID.BANANA_SAPLING, "Banana sapling", Skill.FARMING, 33, 0,
TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING, 35, 7325, CriticalItem.TEAK_SEED), CriticalItem.BANANA_TREE_SEED, null, new ItemStack(ItemID.BANANA_SAPLING, 1)),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING, 55, 15783, CriticalItem.MAHOGANY_SEED), ORANGE_TREE_SEED(ItemID.ORANGE_SAPLING, "Orange sapling", Skill.FARMING, 39, 0,
SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING, 83, 19500, CriticalItem.SPIRIT_SEED), CriticalItem.ORANGE_TREE_SEED, null, new ItemStack(ItemID.ORANGE_SAPLING, 1)),
CURRY_TREE_SEED(ItemID.CURRY_SAPLING, "Curry sapling", Skill.FARMING, 42, 0,
CriticalItem.CURRY_TREE_SEED, null, new ItemStack(ItemID.CURRY_SAPLING, 1)),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SAPLING, "Pineapple sapling", Skill.FARMING, 51, 0,
CriticalItem.PINEAPPLE_SEED, null, new ItemStack(ItemID.PINEAPPLE_SAPLING, 1)),
PAPAYA_TREE_SEED(ItemID.PAPAYA_SAPLING, "Papaya sapling", Skill.FARMING, 57, 0,
CriticalItem.PAPAYA_TREE_SEED, null, new ItemStack(ItemID.PAPAYA_SAPLING, 1)),
PALM_TREE_SEED(ItemID.PALM_SAPLING, "Palm sapling", Skill.FARMING, 68, 0,
CriticalItem.PALM_TREE_SEED, null, new ItemStack(ItemID.PALM_SAPLING, 1)),
CALQUAT_TREE_SEED(ItemID.CALQUAT_SAPLING, "Calquat sapling", Skill.FARMING, 72, 0,
CriticalItem.CALQUAT_TREE_SEED, null, new ItemStack(ItemID.CALQUAT_SAPLING, 1)),
TEAK_SEED(ItemID.TEAK_SAPLING, "Teak sapling", Skill.FARMING, 35, 0,
CriticalItem.TEAK_SEED, null, new ItemStack(ItemID.TEAK_SAPLING, 1)),
MAHOGANY_SEED(ItemID.MAHOGANY_SAPLING, "Mahogany sapling", Skill.FARMING, 55, 0,
CriticalItem.MAHOGANY_SEED, null, new ItemStack(ItemID.MAHOGANY_SAPLING, 1)),
SPIRIT_SEED(ItemID.SPIRIT_SAPLING, "Spirit sapling", Skill.FARMING, 83, 0,
CriticalItem.SPIRIT_SEED, null, new ItemStack(ItemID.SPIRIT_SAPLING, 1)),
OAK_SAPPLING(ItemID.OAK_SAPLING, "Oak tree", Skill.FARMING, 15, 481.3,
CriticalItem.OAK_SAPLING, null, null),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Willow tree", Skill.FARMING, 30, 1481.5,
CriticalItem.WILLOW_SAPLING, null, null),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Maple tree", Skill.FARMING, 45, 3448.4,
CriticalItem.MAPLE_SAPLING, null, null),
YEW_SAPLING(ItemID.YEW_SAPLING, "Yew tree", Skill.FARMING, 60, 7150.9,
CriticalItem.YEW_SAPLING, null, null),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Magic tree", Skill.FARMING, 75, 13913.8,
CriticalItem.MAGIC_SAPLING, null, null),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Apple tree", Skill.FARMING, 27, 1272.5,
CriticalItem.APPLE_TREE_SAPLING, null, null),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Banana tree", Skill.FARMING, 33, 1841.5,
CriticalItem.BANANA_TREE_SAPLING, null, null),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Orange tree", Skill.FARMING, 39, 2586.7,
CriticalItem.ORANGE_TREE_SAPLING, null, null),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Curry tree", Skill.FARMING, 42, 3036.9,
CriticalItem.CURRY_TREE_SAPLING, null, null),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Pineapple tree", Skill.FARMING, 51, 4791.7,
CriticalItem.PINEAPPLE_SAPLING, null, null),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Papaya tree", Skill.FARMING, 57, 6380.4,
CriticalItem.PAPAYA_TREE_SAPLING, null, null),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Palm tree", Skill.FARMING, 68, 10509.6,
CriticalItem.PALM_TREE_SAPLING, null, null),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Calquat tree", Skill.FARMING, 72, 12516.5,
CriticalItem.CALQUAT_TREE_SAPLING, null, null),
TEAK_SAPLING(ItemID.TEAK_SAPLING, "Teak tree", Skill.FARMING, 35, 7325,
CriticalItem.TEAK_SAPLING, null, null),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Mahogany tree", Skill.FARMING, 55, 15783,
CriticalItem.MAHOGANY_SAPLING, null, null),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Spirit tree", Skill.FARMING, 83, 19500,
CriticalItem.SPIRIT_SAPLING, null, null),
; ;
private final int icon; private final int icon;
private final String name; private final String name;
private final CriticalItem criticalItem;
private final Skill skill; private final Skill skill;
private final int level; private final int level;
private final double xp; private final double xp;
private final SecondaryItem[] secondaries; private final ItemStack[] secondaries;
private final CriticalItem criticalItem; @Nullable
private final boolean preventLinked; private final ItemStack output;
private ItemInfo outputItemInfo = null;
@Nullable
private final CriticalItem linkedItem;
Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem) // Store activity by CriticalItem
{ private static final ImmutableMultimap<CriticalItem, Activity> CRITICAL_MAP;
this.icon = Icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = new SecondaryItem[0];
this.preventLinked = false;
}
Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries) static
{ {
this.icon = Icon; final ImmutableMultimap.Builder<CriticalItem, Activity> map = ImmutableMultimap.builder();
this.name = name; for (final Activity item : values())
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems();
this.preventLinked = false;
}
Activity(final int Icon, final String name, final Skill skill, final int level, final double xp, final CriticalItem criticalItem, final ActivitySecondaries secondaries, final boolean preventLinked)
{
this.icon = Icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems();
this.preventLinked = preventLinked;
}
// Builds a Map to reduce looping frequency
private static Map<CriticalItem, ArrayList<Activity>> buildItemMap()
{
Map<CriticalItem, ArrayList<Activity>> map = new HashMap<>();
for (Activity item : values())
{ {
map.computeIfAbsent(item.getCriticalItem(), e -> new ArrayList<>()).add(item); map.put(item.getCriticalItem(), item);
} }
CRITICAL_MAP = map.build();
return map;
} }
private static final Map<CriticalItem, ArrayList<Activity>> byCriticalItem = buildItemMap(); Activity(
final int icon,
public static List<Activity> getByCriticalItem(CriticalItem item) final String name,
final Skill skill,
final int level,
final double xp,
final CriticalItem criticalItem,
@Nullable final Secondaries secondaries,
@Nullable final ItemStack output)
{ {
this.icon = icon;
return byCriticalItem.getOrDefault(item, new ArrayList<>()); this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new ItemStack[0] : secondaries.getItems();
this.output = output;
this.linkedItem = output == null ? null : CriticalItem.getByItemId(output.getId());
} }
/** /**
* Get all Activities for this CriticalItem * Get all Activities for this CriticalItem
* *
* @param item CriticalItem to check for * @param item CriticalItem to check for
* @param limitLevel Level to check Activitiy requirements against. -1 or 0 value disables limits * @return an empty Collection if no activities
* @return an empty list if no activities
*/ */
public static List<Activity> getByCriticalItem(CriticalItem item, int limitLevel) public static List<Activity> getByCriticalItem(CriticalItem item)
{ {
List<Activity> activities = getByCriticalItem(item); final Collection<Activity> activities = CRITICAL_MAP.get(item);
List<Activity> l = new ArrayList<>(); if (activities == null)
{
return new ArrayList<>();
}
return new ArrayList<>(activities);
}
/**
* Get all Activities for this CriticalItem limited to level
*
* @param item CriticalItem to check for
* @param limitLevel Level to check Activitiy requirements against. -1/0 value disables limits
* @return an empty Collection if no activities
*/
public static List<Activity> getByCriticalItem(final CriticalItem item, final int limitLevel)
{
// Return as list to allow getting by index
final List<Activity> l = getByCriticalItem(item);
if (limitLevel <= 0) if (limitLevel <= 0)
{ {
return l; return l;
} }
for (Activity a : activities) return l.stream().filter(a -> a.getLevel() <= limitLevel).collect(Collectors.toList());
{
if (!(a.getLevel() > limitLevel))
{
l.add(a);
}
}
return l;
} }
}
/**
* Attaches the Item Composition to each CriticalItem on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (Activity a : values())
{
final ItemStack output = a.getOutput();
if (output == null)
{
continue;
}
if (a.getOutputItemInfo() != null)
{
return;
}
final ItemDefinition c = m.getItemDefinition(output.getId());
a.outputItemInfo = new ItemInfo(c.getName(), c.isStackable());
}
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.beans;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.ItemID;
@Getter(AccessLevel.PUBLIC)
public enum ActivitySecondaries
{
/**
* Herblore
*/
UNFINISHED_POTION(new SecondaryItem(ItemID.VIAL_OF_WATER, 1)),
SWAMP_TAR(new SecondaryItem(ItemID.SWAMP_TAR, 15)),
// Guam
ATTACK_POTION(new SecondaryItem(ItemID.EYE_OF_NEWT)),
// Marrentil
ANTIPOISON(new SecondaryItem(ItemID.UNICORN_HORN_DUST)),
// Tarromin
STRENGTH_POTION(new SecondaryItem(ItemID.LIMPWURT_ROOT)),
SERUM_207(new SecondaryItem(ItemID.ASHES)),
// Harralander
COMPOST_POTION(new SecondaryItem(ItemID.VOLCANIC_ASH)),
RESTORE_POTION(new SecondaryItem(ItemID.RED_SPIDERS_EGGS)),
ENERGY_POTION(new SecondaryItem(ItemID.CHOCOLATE_DUST)),
COMBAT_POTION(new SecondaryItem(ItemID.GOAT_HORN_DUST)),
// Ranarr Weed
DEFENCE_POTION(new SecondaryItem(ItemID.WHITE_BERRIES)),
PRAYER_POTION(new SecondaryItem(ItemID.SNAPE_GRASS)),
// Toadflax
AGILITY_POTION(new SecondaryItem(ItemID.TOADS_LEGS)),
SARADOMIN_BREW(new SecondaryItem(ItemID.CRUSHED_NEST)),
// Irit
SUPER_ATTACK(new SecondaryItem(ItemID.EYE_OF_NEWT)),
SUPERANTIPOISON(new SecondaryItem(ItemID.UNICORN_HORN_DUST)),
// Avantoe
FISHING_POTION(new SecondaryItem(ItemID.SNAPE_GRASS)),
SUPER_ENERGY_POTION(new SecondaryItem(ItemID.MORT_MYRE_FUNGUS)),
HUNTER_POTION(new SecondaryItem(ItemID.KEBBIT_TEETH_DUST)),
// Kwuarm
SUPER_STRENGTH(new SecondaryItem(ItemID.LIMPWURT_ROOT)),
// Snapdragon
SUPER_RESTORE(new SecondaryItem(ItemID.RED_SPIDERS_EGGS)),
SANFEW_SERUM(new SecondaryItem(ItemID.SNAKE_WEED), new SecondaryItem(ItemID.UNICORN_HORN_DUST), new SecondaryItem(ItemID.SUPER_RESTORE4), new SecondaryItem(ItemID.NAIL_BEAST_NAILS)),
// Cadantine
SUPER_DEFENCE_POTION(new SecondaryItem(ItemID.WHITE_BERRIES)),
// Lantadyme
ANTIFIRE_POTION(new SecondaryItem(ItemID.DRAGON_SCALE_DUST)),
MAGIC_POTION(new SecondaryItem(ItemID.POTATO_CACTUS)),
// Dwarf Weed
RANGING_POTION(new SecondaryItem(ItemID.WINE_OF_ZAMORAK)),
// Torstol
ZAMORAK_BREW(new SecondaryItem(ItemID.JANGERBERRIES)),
SUPER_COMBAT_POTION(new SecondaryItem(ItemID.SUPER_ATTACK3), new SecondaryItem(ItemID.SUPER_STRENGTH3), new SecondaryItem(ItemID.SUPER_DEFENCE3)),
ANTIVENOM_PLUS(new SecondaryItem(ItemID.ANTIVENOM4)),
/**
* Smithing
*/
COAL_ORE(new SecondaryItem(ItemID.COAL)),
COAL_ORE_2(new SecondaryItem(ItemID.COAL, 2)),
COAL_ORE_4(new SecondaryItem(ItemID.COAL, 4)),
COAL_ORE_6(new SecondaryItem(ItemID.COAL, 6)),
COAL_ORE_8(new SecondaryItem(ItemID.COAL, 8)),
/**
* Crafting
*/
GOLD_BAR(new SecondaryItem(ItemID.GOLD_BAR)),
SILVER_BAR(new SecondaryItem(ItemID.SILVER_BAR)),
WATER_ORB(new SecondaryItem(ItemID.WATER_ORB)),
EARTH_ORB(new SecondaryItem(ItemID.EARTH_ORB)),
FIRE_ORB(new SecondaryItem(ItemID.FIRE_ORB)),
AIR_ORB(new SecondaryItem(ItemID.AIR_ORB)),
/**
* Cooking
*/
JUG_OF_WATER(new SecondaryItem(ItemID.JUG_OF_WATER)),
;
private final SecondaryItem[] items;
ActivitySecondaries(final SecondaryItem... items)
{
this.items = items;
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Adam <Adam@sigterm.info> * Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,27 +22,32 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.cache.definitions.sound; package net.runelite.client.plugins.skillcalculator.banked.beans;
public class SoundEffect2Definition import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public class BankedItem
{ {
public int field1085; private final CriticalItem item;
public int[] field1086 = new int[2]; private final int qty;
public int field1087;
public int field1088;
public int field1089;
public int[] field1090 = new int[2];
public int field1091;
public int field1092 = 2;
public int field1093;
public int field1094;
public int field1095;
public SoundEffect2Definition() public double getXpRate()
{ {
this.field1086[0] = 0; final Activity selectedActivity = item.getSelectedActivity();
this.field1086[1] = '\uffff'; if (selectedActivity == null)
this.field1090[0] = 0; {
this.field1090[1] = '\uffff'; return 0;
}
return selectedActivity.getXp();
} }
}
@Override
public String toString()
{
return item.name() + " x " + qty;
}
}

View File

@@ -0,0 +1,355 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.beans;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
@Getter
public enum CriticalItem
{
/**
* Construction Items
*/
// Logs
LOGS(ItemID.LOGS, Skill.CONSTRUCTION, "Logs"),
OAK_LOGS(ItemID.OAK_LOGS, Skill.CONSTRUCTION, "Logs"),
TEAK_LOGS(ItemID.TEAK_LOGS, Skill.CONSTRUCTION, "Logs"),
MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, Skill.CONSTRUCTION, "Logs"),
// Planks
PLANK(ItemID.PLANK, Skill.CONSTRUCTION, "Planks"),
OAK_PLANK(ItemID.OAK_PLANK, Skill.CONSTRUCTION, "Planks"),
TEAK_PLANK(ItemID.TEAK_PLANK, Skill.CONSTRUCTION, "Planks"),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, Skill.CONSTRUCTION, "Planks"),
/**
* Herblore Items
*/
// Grimy Herbs
GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_KWUARM(ItemID.GRIMY_KWUARM, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, Skill.HERBLORE, "Grimy Herbs"),
// Clean Herbs
GUAM_LEAF(ItemID.GUAM_LEAF, Skill.HERBLORE, "Cleaned Herbs"),
MARRENTILL(ItemID.MARRENTILL, Skill.HERBLORE, "Cleaned Herbs"),
TARROMIN(ItemID.TARROMIN, Skill.HERBLORE, "Cleaned Herbs"),
HARRALANDER(ItemID.HARRALANDER, Skill.HERBLORE, "Cleaned Herbs"),
RANARR_WEED(ItemID.RANARR_WEED, Skill.HERBLORE, "Cleaned Herbs"),
TOADFLAX(ItemID.TOADFLAX, Skill.HERBLORE, "Cleaned Herbs"),
IRIT_LEAF(ItemID.IRIT_LEAF, Skill.HERBLORE, "Cleaned Herbs"),
AVANTOE(ItemID.AVANTOE, Skill.HERBLORE, "Cleaned Herbs"),
KWUARM(ItemID.KWUARM, Skill.HERBLORE, "Cleaned Herbs"),
SNAPDRAGON(ItemID.SNAPDRAGON, Skill.HERBLORE, "Cleaned Herbs"),
CADANTINE(ItemID.CADANTINE, Skill.HERBLORE, "Cleaned Herbs"),
LANTADYME(ItemID.LANTADYME, Skill.HERBLORE, "Cleaned Herbs"),
DWARF_WEED(ItemID.DWARF_WEED, Skill.HERBLORE, "Cleaned Herbs"),
TORSTOL(ItemID.TORSTOL, Skill.HERBLORE, "Cleaned Herbs"),
// Unfinished Potions
GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
/**
* Prayer Items
*/
// Bones
BONES(ItemID.BONES, Skill.PRAYER, "Bones"),
WOLF_BONES(ItemID.WOLF_BONES, Skill.PRAYER, "Bones"),
BURNT_BONES(ItemID.BURNT_BONES, Skill.PRAYER, "Bones"),
MONKEY_BONES(ItemID.MONKEY_BONES, Skill.PRAYER, "Bones"),
BAT_BONES(ItemID.BAT_BONES, Skill.PRAYER, "Bones"),
JOGRE_BONES(ItemID.JOGRE_BONES, Skill.PRAYER, "Bones"),
BIG_BONES(ItemID.BIG_BONES, Skill.PRAYER, "Bones"),
ZOGRE_BONES(ItemID.ZOGRE_BONES, Skill.PRAYER, "Bones"),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, Skill.PRAYER, "Bones"),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, Skill.PRAYER, "Bones"),
WYVERN_BONES(ItemID.WYVERN_BONES, Skill.PRAYER, "Bones"),
DRAGON_BONES(ItemID.DRAGON_BONES, Skill.PRAYER, "Bones"),
FAYRG_BONES(ItemID.FAYRG_BONES, Skill.PRAYER, "Bones"),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, Skill.PRAYER, "Bones"),
RAURG_BONES(ItemID.RAURG_BONES, Skill.PRAYER, "Bones"),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, Skill.PRAYER, "Bones"),
OURG_BONES(ItemID.OURG_BONES, Skill.PRAYER, "Bones"),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, Skill.PRAYER, "Bones"),
// Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, Skill.PRAYER, "Shades", true),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, Skill.PRAYER, "Shades", true),
RIYL_REMAINS(ItemID.RIYL_REMAINS, Skill.PRAYER, "Shades", true),
ASYN_REMAINS(ItemID.ASYN_REMAINS, Skill.PRAYER, "Shades", true),
FIYR_REMAINS(ItemID.FIYR_REMAINS, Skill.PRAYER, "Shades", true),
// Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, Skill.PRAYER, "Ensouled Heads", true),
/**
* Cooking Items
*/
RAW_HERRING(ItemID.RAW_HERRING, Skill.COOKING, "Fish"),
RAW_MACKEREL(ItemID.RAW_MACKEREL, Skill.COOKING, "Fish"),
RAW_TROUT(ItemID.RAW_TROUT, Skill.COOKING, "Fish"),
RAW_COD(ItemID.RAW_COD, Skill.COOKING, "Fish"),
RAW_PIKE(ItemID.RAW_PIKE, Skill.COOKING, "Fish"),
RAW_SALMON(ItemID.RAW_SALMON, Skill.COOKING, "Fish"),
RAW_TUNA(ItemID.RAW_TUNA, Skill.COOKING, "Fish"),
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, Skill.COOKING, "Fish"),
RAW_LOBSTER(ItemID.RAW_LOBSTER, Skill.COOKING, "Fish"),
RAW_BASS(ItemID.RAW_BASS, Skill.COOKING, "Fish"),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, Skill.COOKING, "Fish"),
RAW_MONKFISH(ItemID.RAW_MONKFISH, Skill.COOKING, "Fish"),
RAW_SHARK(ItemID.RAW_SHARK, Skill.COOKING, "Fish"),
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, Skill.COOKING, "Fish"),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, Skill.COOKING, "Fish"),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, Skill.COOKING, "Fish"),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, Skill.COOKING, "Fish"),
GRAPES(ItemID.GRAPES, Skill.COOKING, "Other"),
/**
* Crafting Items
*/
WOOL(ItemID.WOOL, Skill.CRAFTING, "Misc"),
FLAX(ItemID.FLAX, Skill.CRAFTING, "Misc"),
MOLTEN_GLASS(ItemID.MOLTEN_GLASS, Skill.CRAFTING, "Misc"),
BATTLESTAFF(ItemID.BATTLESTAFF, Skill.CRAFTING, "Misc"),
// D'hide/Dragon Leather
GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
// Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, Skill.CRAFTING, "Gems"),
UNCUT_JADE(ItemID.UNCUT_JADE, Skill.CRAFTING, "Gems"),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, Skill.CRAFTING, "Gems"),
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, Skill.CRAFTING, "Gems"),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, Skill.CRAFTING, "Gems"),
UNCUT_RUBY(ItemID.UNCUT_RUBY, Skill.CRAFTING, "Gems"),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, Skill.CRAFTING, "Gems"),
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, Skill.CRAFTING, "Gems"),
UNCUT_ONYX(ItemID.UNCUT_ONYX, Skill.CRAFTING, "Gems"),
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, Skill.CRAFTING, "Gems"),
// Cut Gems
OPAL(ItemID.OPAL, Skill.CRAFTING, "Gems"),
JADE(ItemID.JADE, Skill.CRAFTING, "Gems"),
RED_TOPAZ(ItemID.RED_TOPAZ, Skill.CRAFTING, "Gems"),
SAPPHIRE(ItemID.SAPPHIRE, Skill.CRAFTING, "Gems"),
EMERALD(ItemID.EMERALD, Skill.CRAFTING, "Gems"),
RUBY(ItemID.RUBY, Skill.CRAFTING, "Gems"),
DIAMOND(ItemID.DIAMOND, Skill.CRAFTING, "Gems"),
DRAGONSTONE(ItemID.DRAGONSTONE, Skill.CRAFTING, "Gems"),
ONYX(ItemID.ONYX, Skill.CRAFTING, "Gems"),
ZENYTE(ItemID.ZENYTE, Skill.CRAFTING, "Gems"),
/**
* Smithing Items
*/
// Ores
IRON_ORE(ItemID.IRON_ORE, Skill.SMITHING, "Ore"),
SILVER_ORE(ItemID.SILVER_ORE, Skill.SMITHING, "Ore"),
GOLD_ORE(ItemID.GOLD_ORE, Skill.SMITHING, "Ore"),
MITHRIL_ORE(ItemID.MITHRIL_ORE, Skill.SMITHING, "Ore"),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, Skill.SMITHING, "Ore"),
RUNITE_ORE(ItemID.RUNITE_ORE, Skill.SMITHING, "Ore"),
// Bars
BRONZE_BAR(ItemID.BRONZE_BAR, Skill.SMITHING, "Bars"),
IRON_BAR(ItemID.IRON_BAR, Skill.SMITHING, "Bars"),
STEEL_BAR(ItemID.STEEL_BAR, Skill.SMITHING, "Bars"),
MITHRIL_BAR(ItemID.MITHRIL_BAR, Skill.SMITHING, "Bars"),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, Skill.SMITHING, "Bars"),
RUNITE_BAR(ItemID.RUNITE_BAR, Skill.SMITHING, "Bars"),
/**
* Farming Items
*/
// Seeds
ACORN(ItemID.ACORN, Skill.FARMING, "Seeds"),
WILLOW_SEED(ItemID.WILLOW_SEED, Skill.FARMING, "Seeds"),
MAPLE_SEED(ItemID.MAPLE_SEED, Skill.FARMING, "Seeds"),
YEW_SEED(ItemID.YEW_SEED, Skill.FARMING, "Seeds"),
MAGIC_SEED(ItemID.MAGIC_SEED, Skill.FARMING, "Seeds"),
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, Skill.FARMING, "Seeds"),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, Skill.FARMING, "Seeds"),
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, Skill.FARMING, "Seeds"),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, Skill.FARMING, "Seeds"),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, Skill.FARMING, "Seeds"),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, Skill.FARMING, "Seeds"),
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, Skill.FARMING, "Seeds"),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, Skill.FARMING, "Seeds"),
TEAK_SEED(ItemID.TEAK_SEED, Skill.FARMING, "Seeds"),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, Skill.FARMING, "Seeds"),
SPIRIT_SEED(ItemID.SPIRIT_SEED, Skill.FARMING, "Seeds"),
// Saplings
OAK_SAPLING(ItemID.OAK_SAPLING, Skill.FARMING, "Saplings"),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, Skill.FARMING, "Saplings"),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, Skill.FARMING, "Saplings"),
YEW_SAPLING(ItemID.YEW_SAPLING, Skill.FARMING, "Saplings"),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, Skill.FARMING, "Saplings"),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, Skill.FARMING, "Saplings"),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, Skill.FARMING, "Saplings"),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, Skill.FARMING, "Saplings"),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, Skill.FARMING, "Saplings"),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, Skill.FARMING, "Saplings"),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, Skill.FARMING, "Saplings"),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, Skill.FARMING, "Saplings"),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, Skill.FARMING, "Saplings"),
TEAK_SAPLING(ItemID.TEAK_SAPLING, Skill.FARMING, "Saplings"),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, Skill.FARMING, "Saplings"),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, Skill.FARMING, "Saplings"),
;
private final int itemID;
private final Skill skill;
private final String category;
private boolean ignoreBonus;
@Setter
// Stores the item composition info we use since we don't operate on the game thread
private ItemInfo itemInfo = null;
@Setter
private Activity selectedActivity;
private static final Multimap<Skill, CriticalItem> SKILL_MAP = ArrayListMultimap.create();
private static final Map<Integer, CriticalItem> ITEM_ID_MAP = new HashMap<>();
static
{
for (CriticalItem i : values())
{
Skill s = i.getSkill();
SKILL_MAP.put(s, i);
ITEM_ID_MAP.put(i.getItemID(), i);
}
}
CriticalItem(int itemID, Skill skill, String category, boolean ignoreBonus)
{
this.itemID = itemID;
this.category = category;
this.skill = skill;
this.ignoreBonus = ignoreBonus;
}
CriticalItem(int itemID, Skill skill, String category)
{
this(itemID, skill, category, false);
}
public static Collection<CriticalItem> getBySkill(Skill skill)
{
Collection<CriticalItem> items = SKILL_MAP.get(skill);
if (items == null)
{
items = new ArrayList<>();
}
return items;
}
public static CriticalItem getByItemId(int id)
{
return ITEM_ID_MAP.get(id);
}
/**
* Attaches the Item Composition to each CriticalItem on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (CriticalItem i : values())
{
if (i.itemInfo != null)
{
return;
}
final ItemDefinition c = m.getItemDefinition(i.getItemID());
i.itemInfo = new ItemInfo(c.getName(), c.isStackable());
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle> * Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -24,23 +24,13 @@
*/ */
package net.runelite.client.plugins.skillcalculator.banked.beans; package net.runelite.client.plugins.skillcalculator.banked.beans;
import lombok.AccessLevel; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Data;
@Getter(AccessLevel.PUBLIC) @Data
public class SecondaryItem @AllArgsConstructor
public class ItemInfo
{ {
private final int id; private String name;
private final int qty; private boolean stackable;
}
SecondaryItem(int id, int qty)
{
this.id = id;
this.qty = qty;
}
SecondaryItem(int id)
{
this(id, 1);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar> * Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,22 +22,15 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.runenergy; package net.runelite.client.plugins.skillcalculator.banked.beans;
import net.runelite.client.config.Config; import lombok.AllArgsConstructor;
import net.runelite.client.config.ConfigGroup; import lombok.Data;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("runenergy") @Data
public interface RunEnergyConfig extends Config @AllArgsConstructor
class ItemStack
{ {
@ConfigItem( private int id;
keyName = "replaceOrbText", private int qty;
name = "Replace orb text with run time left", }
description = "Show the remaining run time (in seconds) next in the energy orb."
)
default boolean replaceOrbText()
{
return false;
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.beans;
import lombok.Getter;
import net.runelite.api.ItemID;
@Getter
public enum Secondaries
{
/**
* Herblore
*/
UNFINISHED_POTION(new ItemStack(ItemID.VIAL_OF_WATER, 1)),
SWAMP_TAR(new ItemStack(ItemID.SWAMP_TAR, 15)),
// Guam
ATTACK_POTION(new ItemStack(ItemID.EYE_OF_NEWT, 1)),
// Marrentil
ANTIPOISON(new ItemStack(ItemID.UNICORN_HORN_DUST, 1)),
// Tarromin
STRENGTH_POTION(new ItemStack(ItemID.LIMPWURT_ROOT, 1)),
SERUM_207(new ItemStack(ItemID.ASHES, 1)),
// Harralander
COMPOST_POTION(new ItemStack(ItemID.VOLCANIC_ASH, 1)),
RESTORE_POTION(new ItemStack(ItemID.RED_SPIDERS_EGGS, 1)),
ENERGY_POTION(new ItemStack(ItemID.CHOCOLATE_DUST, 1)),
COMBAT_POTION(new ItemStack(ItemID.GOAT_HORN_DUST, 1)),
// Ranarr Weed
DEFENCE_POTION(new ItemStack(ItemID.WHITE_BERRIES, 1)),
PRAYER_POTION(new ItemStack(ItemID.SNAPE_GRASS, 1)),
// Toadflax
AGILITY_POTION(new ItemStack(ItemID.TOADS_LEGS, 1)),
SARADOMIN_BREW(new ItemStack(ItemID.CRUSHED_NEST, 1)),
// Irit
SUPER_ATTACK(new ItemStack(ItemID.EYE_OF_NEWT, 1)),
SUPERANTIPOISON(new ItemStack(ItemID.UNICORN_HORN_DUST, 1)),
// Avantoe
FISHING_POTION(new ItemStack(ItemID.SNAPE_GRASS, 1)),
SUPER_ENERGY_POTION(new ItemStack(ItemID.MORT_MYRE_FUNGUS, 1)),
HUNTER_POTION(new ItemStack(ItemID.KEBBIT_TEETH_DUST, 1)),
// Kwuarm
SUPER_STRENGTH(new ItemStack(ItemID.LIMPWURT_ROOT, 1)),
// Snapdragon
SUPER_RESTORE(new ItemStack(ItemID.RED_SPIDERS_EGGS, 1)),
SANFEW_SERUM(new ItemStack(ItemID.SNAKE_WEED, 1), new ItemStack(ItemID.UNICORN_HORN_DUST, 1), new ItemStack(ItemID.SUPER_RESTORE4, 1), new ItemStack(ItemID.NAIL_BEAST_NAILS, 1)),
// Cadantine
SUPER_DEFENCE_POTION(new ItemStack(ItemID.WHITE_BERRIES, 1)),
// Lantadyme
ANTIFIRE_POTION(new ItemStack(ItemID.DRAGON_SCALE_DUST, 1)),
MAGIC_POTION(new ItemStack(ItemID.POTATO_CACTUS, 1)),
// Dwarf Weed
RANGING_POTION(new ItemStack(ItemID.WINE_OF_ZAMORAK, 1)),
// Torstol
ZAMORAK_BREW(new ItemStack(ItemID.JANGERBERRIES, 1)),
SUPER_COMBAT_POTION(new ItemStack(ItemID.SUPER_ATTACK4, 1), new ItemStack(ItemID.SUPER_STRENGTH4, 1), new ItemStack(ItemID.SUPER_DEFENCE4, 1)),
ANTIVENOM_PLUS(new ItemStack(ItemID.ANTIVENOM4, 1)),
/**
* Smithing
*/
COAL_ORE(new ItemStack(ItemID.COAL, 1)),
COAL_ORE_2(new ItemStack(ItemID.COAL, 2)),
COAL_ORE_4(new ItemStack(ItemID.COAL, 4)),
COAL_ORE_6(new ItemStack(ItemID.COAL, 6)),
COAL_ORE_8(new ItemStack(ItemID.COAL, 8)),
/**
* Crafting
*/
GOLD_BAR(new ItemStack(ItemID.GOLD_BAR, 1)),
SILVER_BAR(new ItemStack(ItemID.SILVER_BAR, 1)),
WATER_ORB(new ItemStack(ItemID.WATER_ORB, 1)),
EARTH_ORB(new ItemStack(ItemID.EARTH_ORB, 1)),
FIRE_ORB(new ItemStack(ItemID.FIRE_ORB, 1)),
AIR_ORB(new ItemStack(ItemID.AIR_ORB, 1)),
/**
* Construction
*/
COINS_100(new ItemStack(ItemID.COINS_995, 100)),
COINS_250(new ItemStack(ItemID.COINS_995, 250)),
COINS_500(new ItemStack(ItemID.COINS_995, 500)),
COINS_1500(new ItemStack(ItemID.COINS_995, 1500)),
/**
* Cooking
*/
JUG_OF_WATER(new ItemStack(ItemID.JUG_OF_WATER, 1)),
;
private final ItemStack[] items;
Secondaries(ItemStack... items)
{
this.items = items;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.beans;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.util.Collection;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.Skill;
@AllArgsConstructor
@Getter
public enum XpModifiers
{
LIT_GILDER_ALTAR(Skill.PRAYER, "Lit Gilded Altar (350%)", 3.5f),
ECTOFUNTUS(Skill.PRAYER, "Ectofuntus (400%)", 4),
WILDY_ALTAR(Skill.PRAYER, "Wildy Altar (700%)", 7),
FARMERS_OUTFIT(Skill.FARMING, "Farmer's Outfit (+2.5%)", 1.025f);
private final Skill skill;
private final String name;
private final float modifier;
private final static Multimap<Skill, XpModifiers> MODIFIERS_MAP;
static
{
final ImmutableMultimap.Builder<Skill, XpModifiers> map = ImmutableMultimap.builder();
for (final XpModifiers m : values())
{
map.put(m.skill, m);
}
MODIFIERS_MAP = map.build();
}
public static Collection<XpModifiers> getModifiersBySkill(final Skill skill)
{
return MODIFIERS_MAP.get(skill);
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.components;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.BooleanSupplier;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.ui.ColorScheme;
@Getter(AccessLevel.PUBLIC)
public class GridItem extends JLabel
{
private final static String IGNORE = "Ignore Item";
private final static String INCLUDE = "Include Item";
private static final Color UNSELECTED_BACKGROUND = ColorScheme.DARKER_GRAY_COLOR;
private static final Color UNSELECTED_HOVER_BACKGROUND = ColorScheme.DARKER_GRAY_HOVER_COLOR;
private static final Color SELECTED_BACKGROUND = new Color(0, 70, 0);
private static final Color SELECTED_HOVER_BACKGROUND = new Color(0, 100, 0);
private static final Color IGNORED_BACKGROUND = new Color(90, 0, 0);
private static final Color IGNORED_HOVER_BACKGROUND = new Color(120, 0, 0);
/* To be executed when this element is clicked */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onSelectEvent;
/* To be executed when this element is ignored */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onIgnoreEvent;
private final SelectionGrid parent;
private final BankedItem bankedItem;
private int amount;
private boolean selected = false;
private boolean ignored = false;
private final JMenuItem IGNORE_OPTION = new JMenuItem(IGNORE);
GridItem(final SelectionGrid parent, final BankedItem item, final AsyncBufferedImage icon, final int amount)
{
super("");
this.parent = parent;
this.bankedItem = item;
this.setOpaque(true);
this.setBackground(ColorScheme.DARKER_GRAY_COLOR);
this.setBorder(BorderFactory.createEmptyBorder(5, 0, 2, 0));
this.setVerticalAlignment(SwingConstants.CENTER);
this.setHorizontalAlignment(SwingConstants.CENTER);
updateIcon(icon, amount);
updateToolTip();
this.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getButton() == MouseEvent.BUTTON1)
{
select();
}
}
@Override
public void mouseEntered(MouseEvent e)
{
final GridItem item = (GridItem) e.getSource();
item.setBackground(getHoverBackgroundColor());
}
@Override
public void mouseExited(MouseEvent e)
{
final GridItem item = (GridItem) e.getSource();
item.setBackground(getBackgroundColor());
}
});
IGNORE_OPTION.addActionListener(e ->
{
// Update ignored flag now so event knows new state
this.ignored = !this.ignored;
if (onIgnoreEvent != null && !onIgnoreEvent.getAsBoolean())
{
// Reset state
this.ignored = !this.ignored;
return;
}
IGNORE_OPTION.setText(this.ignored ? INCLUDE : IGNORE);
this.setBackground(getBackgroundColor());
});
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(IGNORE_OPTION);
this.setComponentPopupMenu(popupMenu);
}
private Color getBackgroundColor()
{
return ignored ? IGNORED_BACKGROUND : (selected ? SELECTED_BACKGROUND : UNSELECTED_BACKGROUND);
}
private Color getHoverBackgroundColor()
{
return ignored ? IGNORED_HOVER_BACKGROUND : (selected ? SELECTED_HOVER_BACKGROUND : UNSELECTED_HOVER_BACKGROUND);
}
public void select()
{
if (onSelectEvent != null && !onSelectEvent.getAsBoolean())
{
return;
}
selected = true;
setBackground(getBackgroundColor());
}
void unselect()
{
selected = false;
setBackground(getBackgroundColor());
}
public void updateIcon(final AsyncBufferedImage icon, final int amount)
{
icon.addTo(this);
this.amount = amount;
}
public void updateToolTip()
{
this.setToolTipText(buildToolTip());
}
private String buildToolTip()
{
String tip = "<html>" + bankedItem.getItem().getItemInfo().getName();
final Activity a = bankedItem.getItem().getSelectedActivity();
if (a != null)
{
final double xp = parent.getCalc().getItemXpRate(bankedItem);
tip += "<br/>Activity: " + a.getName();
tip += "<br/>Xp/Action: " + BankedCalculator.XP_FORMAT_COMMA.format(xp);
tip += "<br/>Total Xp: " + BankedCalculator.XP_FORMAT_COMMA.format(xp * amount);
}
else
{
tip += "<br/>Outputs: " + bankedItem.getItem().getItemInfo().getName();
}
return tip + "</html>";
}
}

View File

@@ -0,0 +1,354 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.components;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ItemEvent;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Constants;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.ComboBoxIconEntry;
import net.runelite.client.ui.components.ComboBoxListRenderer;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
public class ModifyPanel extends JPanel
{
private static final Dimension ICON_SIZE = new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT);
private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#");
private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0);
private static final Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR;
private final BankedCalculator calc;
private final ItemManager itemManager;
@Getter(AccessLevel.PUBLIC)
private BankedItem bankedItem;
private Map<CriticalItem, Integer> linkedMap;
@Getter(AccessLevel.PUBLIC)
private int amount = 0;
@Getter(AccessLevel.PUBLIC)
private double total = 0;
// Banked item information display
private final JPanel labelContainer;
private final JLabel image;
private final JShadowedLabel labelName;
private final JShadowedLabel labelValue;
// Elements used to adjust banked item
private final JPanel adjustContainer;
public ModifyPanel(final BankedCalculator calc, final ItemManager itemManager)
{
this.calc = calc;
this.itemManager = itemManager;
this.setLayout(new GridBagLayout());
this.setBorder(PANEL_BORDER);
this.setBackground(ColorScheme.DARK_GRAY_COLOR);
// Banked item information display
labelContainer = new JPanel();
labelContainer.setLayout(new BorderLayout());
labelContainer.setBackground(BACKGROUND_COLOR);
labelContainer.setBorder(new EmptyBorder(5, 0, 5, 0));
// Icon
image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
// Wrapper panel for the shadowed labels
final JPanel uiInfo = new JPanel(new GridLayout(2, 1));
uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0));
uiInfo.setBackground(BACKGROUND_COLOR);
labelName = new JShadowedLabel();
labelName.setForeground(Color.WHITE);
labelName.setVerticalAlignment(SwingUtilities.BOTTOM);
labelValue = new JShadowedLabel();
labelValue.setFont(FontManager.getRunescapeSmallFont());
labelValue.setVerticalAlignment(SwingUtilities.TOP);
uiInfo.add(labelName);
uiInfo.add(labelValue);
// Append elements to item info panel
labelContainer.add(image, BorderLayout.LINE_START);
labelContainer.add(uiInfo, BorderLayout.CENTER);
// Container for tools to adjust banked calculation for this item
adjustContainer = new JPanel();
adjustContainer.setLayout(new GridBagLayout());
adjustContainer.setBackground(BACKGROUND_COLOR);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
this.add(labelContainer, c);
c.gridy++;
this.add(adjustContainer, c);
}
// Updates the UI for the selected item
public void setBankedItem(final BankedItem bankedItem)
{
if (bankedItem == null)
{
return;
}
this.bankedItem = bankedItem;
if (this.calc.getConfig().cascadeBankedXp())
{
this.linkedMap = this.calc.createLinksMap(bankedItem);
this.amount = bankedItem.getQty();
for (int i : linkedMap.values())
{
this.amount += i;
}
}
else
{
this.linkedMap = new HashMap<>();
this.amount = this.calc.getItemQty(bankedItem);
}
updateImageTooltip();
updateLabelContainer();
updateAdjustContainer();
}
private void updateImageTooltip()
{
final StringBuilder b = new StringBuilder("<html>");
b.append(bankedItem.getQty()).append(" x ").append(bankedItem.getItem().getItemInfo().getName());
for (final Map.Entry<CriticalItem, Integer> e : this.linkedMap.entrySet())
{
b.append("<br/>").append(e.getValue()).append(" x ").append(e.getKey().getItemInfo().getName());
}
b.append("</html>");
this.image.setToolTipText(b.toString());
}
private void updateLabelContainer()
{
final CriticalItem item = bankedItem.getItem();
// Update image icon
final boolean stackable = item.getItemInfo().isStackable() || amount > 1;
final AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, stackable);
final Runnable resize = () -> image.setIcon(new ImageIcon(icon.getScaledInstance(ICON_SIZE.width, ICON_SIZE.height, Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
final String itemName = item.getItemInfo().getName();
labelName.setText(itemName);
double xp = calc.getItemXpRate(bankedItem);
total = amount * xp;
final String value = FORMAT_COMMA.format(total) + "xp";
labelValue.setText(value);
labelContainer.setToolTipText("<html>" + itemName
+ "<br/>xp: " + xp
+ "<br/>Total: " + total + "</html");
labelContainer.revalidate();
labelContainer.repaint();
}
private void updateAdjustContainer()
{
adjustContainer.removeAll();
final JLabel label = new JLabel("Output:");
label.setVerticalAlignment(JLabel.CENTER);
label.setHorizontalAlignment(JLabel.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
adjustContainer.add(label, c);
c.gridy++;
final float xpFactor = (bankedItem.getItem().isIgnoreBonus() ? 1.0f : this.calc.getXpFactor());
final List<Activity> activities = Activity.getByCriticalItem(bankedItem.getItem(), calc.getSkillLevel());
if (activities == null || activities.size() == 0)
{
adjustContainer.add(new JLabel("Unknown"));
}
else if (activities.size() == 1)
{
final Activity a = activities.get(0);
final AsyncBufferedImage img = itemManager.getImage(a.getIcon());
final ImageIcon icon = new ImageIcon(img);
final double xp = a.getXp() * xpFactor;
final JPanel container = createShadowedLabel(icon, a.getName(), FORMAT_COMMA.format(xp) + "xp");
img.onChanged(() ->
{
icon.setImage(img);
container.repaint();
});
adjustContainer.add(container, c);
}
else
{
final JComboBox<ComboBoxIconEntry> dropdown = new JComboBox<>();
final ComboBoxListRenderer renderer = new ComboBoxListRenderer();
dropdown.setRenderer(renderer);
for (final Activity option : activities)
{
final double xp = option.getXp() * xpFactor;
String name = option.getName();
if (xp > 0)
{
name += " (" + FORMAT_COMMA.format(xp) + "xp)";
}
final AsyncBufferedImage img = itemManager.getImage(option.getIcon());
final ImageIcon icon = new ImageIcon(img);
final ComboBoxIconEntry entry = new ComboBoxIconEntry(icon, name, option);
dropdown.addItem(entry);
img.onChanged(() ->
{
icon.setImage(img);
dropdown.revalidate();
dropdown.repaint();
});
final Activity selected = bankedItem.getItem().getSelectedActivity();
if (option.equals(selected))
{
dropdown.setSelectedItem(entry);
}
}
// Add click event handler now to prevent above code from triggering it.
dropdown.addItemListener(e ->
{
if (e.getStateChange() == ItemEvent.SELECTED && e.getItem() instanceof ComboBoxIconEntry)
{
final ComboBoxIconEntry source = (ComboBoxIconEntry) e.getItem();
if (source.getData() instanceof Activity)
{
final Activity selectedActivity = ((Activity) source.getData());
calc.activitySelected(bankedItem, selectedActivity);
updateLabelContainer();
}
}
});
adjustContainer.add(dropdown, c);
}
}
private JPanel createShadowedLabel(final ImageIcon icon, final String name, final String value)
{
// Wrapper panel for the shadowed labels
final JPanel wrapper = new JPanel(new GridLayout(2, 1));
wrapper.setBorder(new EmptyBorder(0, 5, 0, 0));
wrapper.setBackground(BACKGROUND_COLOR);
final JShadowedLabel nameLabel = new JShadowedLabel(name);
nameLabel.setForeground(Color.WHITE);
nameLabel.setVerticalAlignment(SwingUtilities.BOTTOM);
final JShadowedLabel valueLabel = new JShadowedLabel(value);
valueLabel.setFont(FontManager.getRunescapeSmallFont());
valueLabel.setVerticalAlignment(SwingUtilities.TOP);
wrapper.add(nameLabel);
wrapper.add(valueLabel);
final JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.setBackground(BACKGROUND_COLOR);
container.setBorder(new EmptyBorder(5, 0, 5, 0));
final JLabel image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
image.setIcon(icon);
container.add(image, BorderLayout.LINE_START);
container.add(wrapper, BorderLayout.CENTER);
return container;
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.components;
import java.awt.GridLayout;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
import javax.swing.JPanel;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
/**
* A grid that supports mouse events
*/
public class SelectionGrid extends JPanel
{
private static final int ITEMS_PER_ROW = 5;
@Getter(AccessLevel.PUBLIC)
private final Map<BankedItem, GridItem> panelMap = new LinkedHashMap<>();
@Getter(AccessLevel.PUBLIC)
private BankedItem selectedItem;
@Getter(AccessLevel.PUBLIC)
private BankedItem lastIgnoredItem;
/* To be executed when this element is clicked */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onSelectEvent;
/* To be executed when this element is ignored */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onIgnoreEvent;
@Getter(AccessLevel.PUBLIC)
private final BankedCalculator calc;
public SelectionGrid(final BankedCalculator calc, final Collection<BankedItem> items, final ItemManager itemManager)
{
this.calc = calc;
// Create a panel for every item
for (final BankedItem item : items)
{
final int qty = calc.getItemQty(item);
final boolean stackable = item.getItem().getItemInfo().isStackable() || qty > 1;
final AsyncBufferedImage img = itemManager.getImage(item.getItem().getItemID(), qty, stackable);
final GridItem gridItem = new GridItem(this, item, img, qty);
gridItem.setOnSelectEvent(() -> selected(item));
gridItem.setOnIgnoreEvent(() -> ignore(item));
panelMap.put(item, gridItem);
}
refreshGridDisplay();
}
public void refreshGridDisplay()
{
this.removeAll();
final List<GridItem> items = panelMap.values().stream().filter(gi -> gi.getAmount() > 0).collect(Collectors.toList());
// Calculates how many rows need to be display to fit all items
final int rowSize = ((items.size() % ITEMS_PER_ROW == 0) ? 0 : 1) + items.size() / ITEMS_PER_ROW;
setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1));
for (final GridItem gridItem : items)
{
// Select the first option
if (selectedItem == null)
{
gridItem.select();
}
this.add(gridItem);
}
}
private boolean selected(final BankedItem item)
{
final BankedItem old = this.selectedItem;
if (item.equals(old))
{
return false;
}
// Set selected item now so the boolean can see what was just clicked
this.selectedItem = item;
if (onSelectEvent != null && !onSelectEvent.getAsBoolean())
{
this.selectedItem = old;
return false;
}
final GridItem gridItem = panelMap.get(old);
if (gridItem != null)
{
gridItem.unselect();
}
return true;
}
private boolean ignore(final BankedItem item)
{
this.lastIgnoredItem = item;
return onIgnoreEvent.getAsBoolean();
}
}

View File

@@ -1,402 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.skillcalculator.banked.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.inject.Singleton;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.materialtabs.MaterialTab;
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
import net.runelite.client.util.StackFormatter;
@Singleton
public class CriticalItemPanel extends JPanel
{
private static final Dimension ICON_SIZE = new Dimension(36, 36);
private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#");
private static final BufferedImage ICON_SETTINGS;
private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0);
private final static Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR;
private final static Color BUTTON_HOVER_COLOR = ColorScheme.DARKER_GRAY_HOVER_COLOR;
static
{
BufferedImage i1;
try
{
synchronized (ImageIO.class)
{
i1 = ImageIO.read(BankedCalculator.class.getResourceAsStream("view-more-white.png"));
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
ICON_SETTINGS = i1;
}
private final BankedCalculator bankedCalculator;
private final CriticalItem item;
private final ItemManager itemManager;
private double xp;
@Getter(AccessLevel.PUBLIC)
private int amount;
@Getter(AccessLevel.PUBLIC)
private double total;
private Map<CriticalItem, Integer> linkedMap;
private JShadowedLabel labelValue;
private final JPanel infoContainer;
private final JLabel image;
private boolean infoVisibility = false;
public CriticalItemPanel(BankedCalculator bankedCalculator, ItemManager itemManager, CriticalItem item, double xp, int amount, Map<CriticalItem, Integer> linkedMap)
{
this.bankedCalculator = bankedCalculator;
this.item = item;
this.xp = xp;
this.amount = amount;
this.total = xp * amount;
this.itemManager = itemManager;
this.linkedMap = linkedMap;
this.setLayout(new GridBagLayout());
this.setBorder(PANEL_BORDER);
this.setBackground(ColorScheme.DARK_GRAY_COLOR);
this.setVisible(this.amount > 0);
infoContainer = new JPanel();
infoContainer.setLayout(new GridBagLayout());
infoContainer.setVisible(false);
infoContainer.setBackground(BACKGROUND_COLOR);
infoContainer.setBorder(new MatteBorder(1, 0, 0, 0, Color.GRAY));
// Icon
AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getDefinition().isStackable() || amount > 1);
image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
// Container for Info
JPanel uiInfo = new JPanel(new GridLayout(2, 1));
uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0));
uiInfo.setBackground(BACKGROUND_COLOR);
JShadowedLabel labelName = new JShadowedLabel(item.getDefinition().getName());
labelName.setForeground(Color.WHITE);
labelName.setVerticalAlignment(SwingUtilities.BOTTOM);
labelValue = new JShadowedLabel();
labelValue.setFont(FontManager.getRunescapeSmallFont());
labelValue.setVerticalAlignment(SwingUtilities.TOP);
updateXp(xp);
uiInfo.add(labelName);
uiInfo.add(labelValue);
// Settings Button
JLabel settingsButton = new JLabel();
settingsButton.setBorder(new EmptyBorder(0, 5, 0, 5));
settingsButton.setIcon(new ImageIcon(ICON_SETTINGS));
settingsButton.setOpaque(true);
settingsButton.setBackground(BACKGROUND_COLOR);
settingsButton.addMouseListener(new MouseAdapter()
{
@Override
public void mouseEntered(MouseEvent e)
{
settingsButton.setBackground(BUTTON_HOVER_COLOR);
}
@Override
public void mouseExited(MouseEvent e)
{
settingsButton.setBackground(BACKGROUND_COLOR);
}
@Override
public void mouseClicked(MouseEvent e)
{
toggleInfo();
}
});
// Create and append elements to container panel
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(BACKGROUND_COLOR);
panel.add(image, BorderLayout.LINE_START);
panel.add(uiInfo, BorderLayout.CENTER);
// Only add button if has activity selection options or linked items
List<Activity> activities = Activity.getByCriticalItem(item);
// If linked map has 1 item and it isn't this item still show breakdown (cleaned herbs into unfinished)
if ((linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null))
|| activities.size() > 1)
{
panel.add(settingsButton, BorderLayout.LINE_END);
}
panel.setToolTipText("<html>" + item.getDefinition().getName()
+ "<br/>xp: " + xp
+ "<br/>Total: " + StackFormatter.quantityToStackSize((long) total) + "</html");
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 20;
this.add(panel, c);
c.gridy++;
this.add(infoContainer, c);
}
private void toggleInfo()
{
infoVisibility = !infoVisibility;
if (infoVisibility)
{
createInfoPanel();
}
else
{
infoContainer.removeAll();
infoContainer.setVisible(false);
infoContainer.revalidate();
infoContainer.repaint();
}
}
private void createInfoPanel()
{
infoContainer.removeAll();
infoContainer.setVisible(true);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
JPanel p = createActivitiesPanel();
if (p != null)
{
infoContainer.add(p, c);
c.gridy++;
}
// Show linked item breakdown, including own items
if (linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null))
{
JLabel l = new JLabel("Item Breakdown");
l.setBorder(new EmptyBorder(3, 0, 3, 0));
l.setHorizontalAlignment(JLabel.CENTER);
infoContainer.add(l, c);
c.gridy++;
JPanel con = new JPanel();
con.setLayout(new GridBagLayout());
con.setBackground(BACKGROUND_COLOR);
for (Map.Entry<CriticalItem, Integer> e : linkedMap.entrySet())
{
// Icon
AsyncBufferedImage icon = itemManager.getImage(e.getKey().getItemID(), e.getValue(), e.getKey().getDefinition().isStackable() || e.getValue() > 1);
JLabel image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
image.setToolTipText(e.getKey().getDefinition().getName());
con.add(image, c);
c.gridx++;
}
c.gridx = 0;
infoContainer.add(con, c);
}
}
private JPanel createActivitiesPanel()
{
List<Activity> activities = Activity.getByCriticalItem(item);
if (activities == null || activities.size() == 1)
{
return null;
}
JPanel p = new JPanel();
p.setBackground(BACKGROUND_COLOR);
p.setLayout(new BorderLayout());
JLabel label = new JLabel("Possible training methods");
MaterialTabGroup group = new MaterialTabGroup();
group.setLayout(new GridLayout(0, 6, 0, 2));
group.setBorder(new MatteBorder(1, 1, 1, 1, Color.BLACK));
Activity selected = this.bankedCalculator.getSelectedActivity(this.item);
boolean s = false;
for (Activity option : activities)
{
AsyncBufferedImage icon = itemManager.getImage(option.getIcon());
MaterialTab matTab = new MaterialTab("", group, null);
matTab.setHorizontalAlignment(SwingUtilities.RIGHT);
matTab.setToolTipText(option.getName());
Runnable resize = () ->
matTab.setIcon(new ImageIcon(icon.getScaledInstance(24, 24, Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
group.addTab(matTab);
// Select first option by default
if (!s)
{
s = true;
group.select(matTab);
}
// Select the option if its their selected activity
if (option.equals(selected))
{
group.select(matTab);
}
// Add click event handler now to prevent above code from triggering it.
matTab.setOnSelectEvent(() ->
{
bankedCalculator.activitySelected(item, option);
return true;
});
}
p.add(label, BorderLayout.NORTH);
p.add(group, BorderLayout.SOUTH);
return p;
}
public void updateXp(double newXpRate)
{
xp = newXpRate;
total = xp * amount;
labelValue.setText(FORMAT_COMMA.format(total) + "xp");
}
public void updateAmount(int newAmount, boolean forceVisible)
{
this.setVisible(newAmount > 0 || forceVisible);
this.amount = newAmount;
AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getDefinition().isStackable() || amount > 1);
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
}
public void updateLinkedMap(Map<CriticalItem, Integer> newLinkedMap)
{
this.linkedMap = newLinkedMap;
int sum = 0;
for (Integer v : newLinkedMap.values())
{
sum += v;
}
this.updateAmount(sum, false);
this.updateXp(xp);
// Refresh info panel if visible
if (infoVisibility)
{
createInfoPanel();
}
}
public void recalculate()
{
updateXp(xp);
}
}

View File

@@ -24,10 +24,9 @@
*/ */
package net.runelite.client.plugins.skillcalculator.beans; package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@Getter(AccessLevel.PUBLIC) @Getter
public class SkillData public class SkillData
{ {
private SkillDataEntry[] actions; private SkillDataEntry[] actions;

View File

@@ -24,10 +24,9 @@
*/ */
package net.runelite.client.plugins.skillcalculator.beans; package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@Getter(AccessLevel.PUBLIC) @Getter
public class SkillDataBonus public class SkillDataBonus
{ {
private String name; private String name;

View File

@@ -24,10 +24,9 @@
*/ */
package net.runelite.client.plugins.skillcalculator.beans; package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@Getter(AccessLevel.PUBLIC) @Getter
public class SkillDataEntry public class SkillDataEntry
{ {
private String name; private String name;

View File

@@ -166,6 +166,17 @@ public interface SlayerConfig extends Config
return true; return true;
} }
@ConfigItem(
position = 14,
keyName = "pointsCommand",
name = "Points Command",
description = "Configures whether the slayer points command is enabled<br> !points"
)
default boolean pointsCommand()
{
return true;
}
// Stored data // Stored data
@ConfigItem( @ConfigItem(
keyName = "taskName", keyName = "taskName",

View File

@@ -139,6 +139,7 @@ public class SlayerPlugin extends Plugin
private static final String TASK_COMMAND_STRING = "!task"; private static final String TASK_COMMAND_STRING = "!task";
private static final Pattern TASK_STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]"); private static final Pattern TASK_STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]");
private static final int TASK_STRING_MAX_LENGTH = 50; private static final int TASK_STRING_MAX_LENGTH = 50;
private static final String POINTS_COMMAND_STRING = "!points";
// Superiors // Superiors
@VisibleForTesting @VisibleForTesting
@@ -280,6 +281,8 @@ public class SlayerPlugin extends Plugin
private boolean taskCommand; private boolean taskCommand;
private String taskName; private String taskName;
private String taskLocation; private String taskLocation;
@Setter(AccessLevel.PACKAGE)
private boolean pointsCommand;
private int amount; private int amount;
private int initialAmount; private int initialAmount;
private int lastCertainAmount; private int lastCertainAmount;
@@ -316,6 +319,8 @@ public class SlayerPlugin extends Plugin
clientToolbar.addNavigation(navButton); clientToolbar.addNavigation(navButton);
chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit); chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit);
chatCommandManager.registerCommandAsync(POINTS_COMMAND_STRING, this::pointsLookup); //here
} }
@Override @Override
@@ -329,6 +334,7 @@ public class SlayerPlugin extends Plugin
clearTrackedNPCs(); clearTrackedNPCs();
chatCommandManager.unregisterCommand(TASK_COMMAND_STRING); chatCommandManager.unregisterCommand(TASK_COMMAND_STRING);
chatCommandManager.unregisterCommand(POINTS_COMMAND_STRING);
clientToolbar.removeNavigation(navButton); clientToolbar.removeNavigation(navButton);
} }
@@ -1121,6 +1127,44 @@ public class SlayerPlugin extends Plugin
client.refreshChat(); client.refreshChat();
} }
void pointsLookup(ChatMessage chatMessage, String message)
{
if (!this.pointsCommand)
{
return;
}
ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATECHATOUT))
{
player = client.getLocalPlayer().getName();
}
else
{
player = Text.removeTags(chatMessage.getName())
.replace('\u00A0', ' ');
}
if (Integer.toString(getPoints()) == null)
{
return;
}
String response = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Slayer Points: ")
.append(ChatColorType.HIGHLIGHT)
.append(Integer.toString(getPoints()))
.build();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
}
/* package access method for changing the pause state of the time tracker for the current task */ /* package access method for changing the pause state of the time tracker for the current task */
void setPaused(boolean paused) void setPaused(boolean paused)
{ {
@@ -1208,6 +1252,7 @@ public class SlayerPlugin extends Plugin
this.drawMinimapNames = config.drawMinimapNames(); this.drawMinimapNames = config.drawMinimapNames();
this.weaknessPrompt = config.weaknessPrompt(); this.weaknessPrompt = config.weaknessPrompt();
this.taskCommand = config.taskCommand(); this.taskCommand = config.taskCommand();
this.pointsCommand = config.pointsCommand();
this.taskName = config.taskName(); this.taskName = config.taskName();
this.amount = config.amount(); this.amount = config.amount();
this.initialAmount = config.initialAmount(); this.initialAmount = config.initialAmount();

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 Abex * Copyright (c) 2018 Abex
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,29 +23,47 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.regenmeter; package net.runelite.client.plugins.statusorbs;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Stub;
@ConfigGroup("regenmeter") @ConfigGroup("statusorbs")
public interface RegenMeterConfig extends Config public interface StatusOrbsConfig extends Config
{ {
@ConfigItem( @ConfigItem(
keyName = "showHitpoints", keyName = "hp",
name = "Show hitpoints regen", name = "Hitpoints",
description = "Show a ring around the hitpoints orb") description = "",
default boolean showHitpoints() position = 0
)
default Stub hp()
{
return new Stub();
}
@ConfigItem(
keyName = "dynamicHpHeart",
name = "Dynamic hitpoints heart",
description = "Changes the HP heart color to match players current affliction",
parent = "hp",
position = 1
)
default boolean dynamicHpHeart()
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
keyName = "showSpecial", keyName = "showHitpoints",
name = "Show Spec. Attack regen", name = "Show hitpoints regen",
description = "Show a ring around the Special Attack orb") description = "Show a ring around the hitpoints orb",
default boolean showSpecial() parent = "hp",
position = 2
)
default boolean showHitpoints()
{ {
return true; return true;
} }
@@ -52,7 +71,10 @@ public interface RegenMeterConfig extends Config
@ConfigItem( @ConfigItem(
keyName = "showWhenNoChange", keyName = "showWhenNoChange",
name = "Show hitpoints regen at full hitpoints", name = "Show hitpoints regen at full hitpoints",
description = "Always show the hitpoints regen orb, even if there will be no stat change") description = "Always show the hitpoints regen orb, even if there will be no stat change",
parent = "hp",
position = 3
)
default boolean showWhenNoChange() default boolean showWhenNoChange()
{ {
return false; return false;
@@ -61,10 +83,70 @@ public interface RegenMeterConfig extends Config
@ConfigItem( @ConfigItem(
keyName = "notifyBeforeHpRegenDuration", keyName = "notifyBeforeHpRegenDuration",
name = "Hitpoint Regen Notification (seconds)", name = "Hitpoint Regen Notification (seconds)",
description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification." description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification.",
parent = "hp",
position = 4
) )
default int getNotifyBeforeHpRegenSeconds() default int getNotifyBeforeHpRegenSeconds()
{ {
return 0; return 0;
} }
}
@ConfigItem(
keyName = "spec",
name = "Special attack",
description = "",
position = 5
)
default Stub spec()
{
return new Stub();
}
@ConfigItem(
keyName = "showSpecial",
name = "Show Spec. Attack regen",
description = "Show a ring around the Special Attack orb",
parent = "spec",
position = 6
)
default boolean showSpecial()
{
return true;
}
@ConfigItem(
keyName = "run",
name = "Run energy",
description = "",
position = 7
)
default Stub run()
{
return new Stub();
}
@ConfigItem(
keyName = "showRun",
name = "Show run energy regen",
description = "Show a ring around the run regen orb",
position = 8,
parent = "run"
)
default boolean showRun()
{
return true;
}
@ConfigItem(
keyName = "replaceOrbText",
name = "Replace run orb text with run time left",
description = "Show the remaining run time (in seconds) next in the energy orb",
position = 9,
parent = "run"
)
default boolean replaceOrbText()
{
return false;
}
}

View File

@@ -0,0 +1,228 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.statusorbs;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Point;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.util.Graceful;
import org.apache.commons.lang3.StringUtils;
public class StatusOrbsOverlay extends Overlay
{
private static final Color HITPOINTS_COLOR = brighter(0x9B0703);
private static final Color SPECIAL_COLOR = brighter(0x1E95B0);
private static final Color RUN_COLOR = new Color(255, 215, 0);
private static final Color OVERLAY_COLOR = new Color(255, 255, 255, 60);
private static final double DIAMETER = 26D;
private static final int OFFSET = 27;
private final Client client;
private final StatusOrbsPlugin plugin;
private final TooltipManager tooltipManager;
private long last = System.nanoTime();
private double percentHp;
private double lastHp;
private double percentSpec;
private double lastSpec;
private double percentRun;
private double lastRun;
private static Color brighter(int color)
{
float[] hsv = new float[3];
Color.RGBtoHSB(color >>> 16, (color >> 8) & 0xFF, color & 0xFF, hsv);
return Color.getHSBColor(hsv[0], 1.f, 1.f);
}
@Inject
public StatusOrbsOverlay(Client client, StatusOrbsPlugin plugin, TooltipManager tooltipManager)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
this.tooltipManager = tooltipManager;
}
@Override
public Dimension render(Graphics2D g)
{
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
long current = System.nanoTime();
double ms = (current - last) / (double) 1000000;
if (plugin.isShowHitpoints())
{
if (lastHp == plugin.getHitpointsPercentage() && plugin.getHitpointsPercentage() != 0)
{
percentHp += ms * plugin.getHpPerMs();
}
else
{
percentHp = plugin.getHitpointsPercentage();
lastHp = plugin.getHitpointsPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_HEALTH_ORB, percentHp, HITPOINTS_COLOR);
}
if (plugin.isShowSpecial())
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_ENABLED) == 1)
{
final Widget widget = client.getWidget(WidgetInfo.MINIMAP_SPEC_ORB);
if (widget != null && !widget.isHidden())
{
final Rectangle bounds = widget.getBounds();
g.setColor(OVERLAY_COLOR);
g.fillOval(
bounds.x + OFFSET,
bounds.y + (int) (bounds.height / 2 - (DIAMETER) / 2),
(int) DIAMETER, (int) DIAMETER);
}
}
if (lastSpec == plugin.getSpecialPercentage() && plugin.getSpecialPercentage() != 0)
{
percentSpec += ms * plugin.getSpecPerMs();
}
else
{
percentSpec = plugin.getSpecialPercentage();
lastSpec = plugin.getSpecialPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_SPEC_ORB, percentSpec, SPECIAL_COLOR);
}
if (plugin.isReplaceOrbText())
{
final Widget runOrb = client.getWidget(WidgetInfo.MINIMAP_TOGGLE_RUN_ORB);
if (runOrb == null || runOrb.isHidden())
{
return null;
}
final Rectangle bounds = runOrb.getBounds();
if (bounds.getX() <= 0)
{
return null;
}
final Point mousePosition = client.getMouseCanvasPosition();
if (bounds.contains(mousePosition.getX(), mousePosition.getY()))
{
StringBuilder sb = new StringBuilder();
sb.append("Weight: ").append(client.getWeight()).append(" kg</br>");
if (plugin.isReplaceOrbText())
{
sb.append("Run Energy: ").append(client.getEnergy()).append("%");
}
else
{
sb.append("Run Time Remaining: ").append(plugin.getEstimatedRunTimeRemaining(false));
}
int secondsUntil100 = plugin.getEstimatedRecoverTimeRemaining();
if (secondsUntil100 > 0)
{
final int minutes = (int) Math.floor(secondsUntil100 / 60.0);
final int seconds = (int) Math.floor(secondsUntil100 - (minutes * 60.0));
sb.append("</br>").append("100% Energy In: ").append(minutes).append(':').append(StringUtils.leftPad(Integer.toString(seconds), 2, "0"));
}
tooltipManager.add(new Tooltip(sb.toString()));
}
}
if (plugin.isShowRun())
{
if (lastRun == plugin.getRunPercentage() && plugin.getRunPercentage() != 0)
{
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360000.0;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
percentRun += ms * recoverRate;
}
else
{
percentRun = plugin.getRunPercentage();
lastRun = plugin.getRunPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_RUN_ORB, percentRun, RUN_COLOR);
}
last = current;
return null;
}
private void renderRegen(Graphics2D g, WidgetInfo widgetInfo, double percent, Color color)
{
Widget widget = client.getWidget(widgetInfo);
if (widget == null || widget.isHidden())
{
return;
}
Rectangle bounds = widget.getBounds();
Arc2D.Double arc = new Arc2D.Double(bounds.x + OFFSET, bounds.y + (bounds.height / 2 - DIAMETER / 2), DIAMETER, DIAMETER, 90.d, -360.d * percent, Arc2D.OPEN);
final Stroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
g.setStroke(STROKE);
g.setColor(color);
g.draw(arc);
}
}

View File

@@ -0,0 +1,490 @@
/*
* Copyright (c) 2019, Owain van Brakel <https://github.com/Owain94>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Zimaya <https://github.com/Zimaya>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.statusorbs;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Prayer;
import net.runelite.api.Skill;
import net.runelite.api.SpriteID;
import net.runelite.api.VarPlayer;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.Graceful;
import net.runelite.client.util.ImageUtil;
import org.apache.commons.lang3.StringUtils;
@PluginDescriptor(
name = "Status Orbs",
description = "Configure settings for the Minimap orbs",
tags = {"minimap", "orb", "regen", "energy", "special"}
)
public class StatusOrbsPlugin extends Plugin
{
private static final BufferedImage HEART_DISEASE;
private static final BufferedImage HEART_POISON;
private static final BufferedImage HEART_VENOM;
static
{
HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-DISEASE.png"), 26, 26);
HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-POISON.png"), 26, 26);
HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-VENOM.png"), 26, 26);
}
private static final int SPEC_REGEN_TICKS = 50;
private static final int NORMAL_HP_REGEN_TICKS = 100;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ConfigManager configManager;
@Inject
private StatusOrbsConfig config;
@Inject
private StatusOrbsOverlay overlay;
@Inject
private OverlayManager overlayManager;
@Inject
private Notifier notifier;
@Getter
private double hitpointsPercentage;
@Getter
private double specialPercentage;
@Getter
private double runPercentage;
@Getter
private double hpPerMs;
@Getter
private double specPerMs = (double) 1 / (SPEC_REGEN_TICKS * 600);
// RegenMeter
private int ticksSinceSpecRegen;
private int ticksSinceHPRegen;
private boolean wasRapidHeal;
private double ticksSinceRunRegen;
// Run Energy
private int lastEnergy = 0;
private boolean localPlayerRunningToDestination;
private WorldPoint currPoint;
private WorldPoint prevLocalPlayerLocation;
private BufferedImage heart;
private boolean dynamicHpHeart;
@Getter(AccessLevel.PACKAGE)
private boolean showHitpoints;
private boolean showWhenNoChange;
private int getNotifyBeforeHpRegenSeconds;
@Getter(AccessLevel.PACKAGE)
private boolean showSpecial;
@Getter(AccessLevel.PACKAGE)
private boolean showRun;
@Getter(AccessLevel.PACKAGE)
private boolean replaceOrbText;
@Provides
StatusOrbsConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(StatusOrbsConfig.class);
}
@Override
protected void startUp() throws Exception
{
migrateConfigs();
updateConfig();
overlayManager.add(overlay);
if (this.dynamicHpHeart && client.getGameState().equals(GameState.LOGGED_IN))
{
clientThread.invoke(this::checkHealthIcon);
}
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
localPlayerRunningToDestination = false;
prevLocalPlayerLocation = null;
resetRunOrbText();
if (this.dynamicHpHeart)
{
clientThread.invoke(this::resetHealthIcon);
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("statusorbs"))
{
updateConfig();
switch (event.getKey())
{
case "replaceOrbText":
if (!this.replaceOrbText)
{
resetRunOrbText();
}
break;
case "dynamicHpHeart":
if (this.dynamicHpHeart)
{
checkHealthIcon();
}
else
{
resetHealthIcon();
}
break;
}
}
}
@Subscribe
private void onVarbitChanged(VarbitChanged e)
{
if (this.dynamicHpHeart)
{
checkHealthIcon();
}
boolean isRapidHeal = client.isPrayerActive(Prayer.RAPID_HEAL);
if (wasRapidHeal != isRapidHeal)
{
ticksSinceHPRegen = 0;
}
wasRapidHeal = isRapidHeal;
}
@Subscribe
private void onGameStateChanged(GameStateChanged ev)
{
if (ev.getGameState() == GameState.HOPPING || ev.getGameState() == GameState.LOGIN_SCREEN)
{
ticksSinceHPRegen = -2; // For some reason this makes this accurate
ticksSinceSpecRegen = 0;
ticksSinceRunRegen = -1;
}
}
@Subscribe
public void onGameTick(GameTick event)
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) == 1000)
{
// The recharge doesn't tick when at 100%
ticksSinceSpecRegen = 0;
}
else
{
ticksSinceSpecRegen = (ticksSinceSpecRegen + 1) % SPEC_REGEN_TICKS;
}
specialPercentage = ticksSinceSpecRegen / (double) SPEC_REGEN_TICKS;
int ticksPerHPRegen = NORMAL_HP_REGEN_TICKS;
hpPerMs = ticksPerHPRegen / (double) 6000000;
if (client.isPrayerActive(Prayer.RAPID_HEAL))
{
ticksPerHPRegen /= 2;
hpPerMs *= 2;
}
ticksSinceHPRegen = (ticksSinceHPRegen + 1) % ticksPerHPRegen;
hitpointsPercentage = ticksSinceHPRegen / (double) ticksPerHPRegen;
int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS);
int maxHP = client.getRealSkillLevel(Skill.HITPOINTS);
if (currentHP == maxHP && !this.showWhenNoChange)
{
hitpointsPercentage = 0;
}
else if (currentHP > maxHP)
{
// Show it going down
hitpointsPercentage = 1 - hitpointsPercentage;
}
// Run Energy
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
if (this.getNotifyBeforeHpRegenSeconds > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
{
notifier.notify("[" + client.getLocalPlayer().getName() + "] regenerates their next hitpoint soon!");
}
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
prevLocalPlayerLocation = client.getLocalPlayer().getWorldLocation();
if (this.replaceOrbText)
{
setRunOrbText(getEstimatedRunTimeRemaining(true));
}
int currEnergy = client.getEnergy();
currPoint = client.getLocalPlayer().getWorldLocation();
if (currEnergy == 100 || (prevLocalPlayerLocation != null && currPoint.distanceTo(prevLocalPlayerLocation) > 1) || currEnergy < lastEnergy)
{
ticksSinceRunRegen = 0;
}
else if (currEnergy > lastEnergy)
{
if (runPercentage < 1)
{
ticksSinceRunRegen = (1 - runPercentage) / runRegenPerTick();
ticksSinceRunRegen = ticksSinceRunRegen > 1 ? 1 : ticksSinceRunRegen;
}
else
{
ticksSinceRunRegen = (runPercentage - 1) / runRegenPerTick();
}
}
else
{
ticksSinceRunRegen += 1;
}
runPercentage = ticksSinceRunRegen * runRegenPerTick();
prevLocalPlayerLocation = currPoint;
lastEnergy = currEnergy;
}
private boolean shouldNotifyHpRegenThisTick(int ticksPerHPRegen)
{
// if the configured duration lies between two ticks, choose the earlier tick
final int ticksBeforeHPRegen = ticksPerHPRegen - ticksSinceHPRegen;
final int notifyTick = (int) Math.ceil(this.getNotifyBeforeHpRegenSeconds * 1000d / Constants.GAME_TICK_LENGTH);
return ticksBeforeHPRegen == notifyTick;
}
private void setRunOrbText(String text)
{
Widget runOrbText = client.getWidget(WidgetInfo.MINIMAP_RUN_ORB_TEXT);
if (runOrbText != null)
{
runOrbText.setText(text);
}
}
private void resetRunOrbText()
{
setRunOrbText(Integer.toString(client.getEnergy()));
}
String getEstimatedRunTimeRemaining(boolean inSeconds)
{
// Calculate the amount of energy lost every 2 ticks (0.6 seconds).
// Negative weight has the same depletion effect as 0 kg.
final int effectiveWeight = Math.max(client.getWeight(), 0);
double lossRate = (Math.min(effectiveWeight, 64) / 100.0) + 0.64;
if (client.getVar(Varbits.RUN_SLOWED_DEPLETION_ACTIVE) != 0)
{
lossRate *= 0.3; // Stamina effect reduces energy depletion to 30%
}
// Calculate the number of seconds left
final double secondsLeft = (client.getEnergy() * 0.6) / lossRate;
// Return the text
if (inSeconds)
{
return (int) Math.floor(secondsLeft) + "s";
}
else
{
final int minutes = (int) Math.floor(secondsLeft / 60.0);
final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0));
return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0");
}
}
int getEstimatedRecoverTimeRemaining()
{
if (localPlayerRunningToDestination)
{
return -1;
}
// Calculate the amount of energy recovered every second
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360.0;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
// Calculate the number of seconds left
final double secondsLeft = (100 - client.getEnergy()) / recoverRate;
return (int) secondsLeft;
}
/**
* Check player afflictions to determine health icon
*/
private void checkHealthIcon()
{
BufferedImage newHeart;
int poison = client.getVar(VarPlayer.IS_POISONED);
if (poison >= 1000000)
{
newHeart = HEART_VENOM;
}
else if (poison > 0)
{
newHeart = HEART_POISON;
}
else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0)
{
newHeart = HEART_DISEASE;
}
else
{
heart = null;
resetHealthIcon();
return;
}
// Only update sprites when the heart icon actually changes
if (newHeart != heart)
{
heart = newHeart;
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSprite(heart, client));
}
}
private double runRegenPerTick()
{
double recoverRate = (client.getBoostedSkillLevel(Skill.AGILITY) / 6d + 8) / 100;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
return recoverRate * 1.3;
}
return recoverRate;
}
/**
* Ensure the HP Heart is the default Sprite
*/
private void resetHealthIcon()
{
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON);
}
/**
* Migrates configs from runenergy and regenmeter to this plugin and deletes the old config values.
* This method should be removed after a reasonable amount of time.
*/
@Deprecated
private void migrateConfigs()
{
migrateConfig("regenmeter", "showHitpoints");
migrateConfig("regenmeter", "showSpecial");
migrateConfig("regenmeter", "showWhenNoChange");
migrateConfig("regenmeter", "notifyBeforeHpRegenDuration");
migrateConfig("runenergy", "replaceOrbText");
}
/**
* Wrapper for migrating individual config options
* This method should be removed after a reasonable amount of time.
*
* @param group old group name
* @param key key name to migrate
*/
@Deprecated
private void migrateConfig(String group, String key)
{
String value = configManager.getConfiguration(group, key);
if (value != null)
{
configManager.setConfiguration("statusorbs", key, value);
configManager.unsetConfiguration(group, key);
}
}
private void updateConfig()
{
this.dynamicHpHeart = config.dynamicHpHeart();
this.showHitpoints = config.showHitpoints();
this.showWhenNoChange = config.showWhenNoChange();
this.getNotifyBeforeHpRegenSeconds = config.getNotifyBeforeHpRegenSeconds();
this.showSpecial = config.showSpecial();
this.showRun = config.showRun();
this.replaceOrbText = config.replaceOrbText();
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019, TheStonedTurtle <http://www.github.com/TheStonedTurtle>
* 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.ui.components;
import javax.annotation.Nullable;
import javax.swing.Icon;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Used with ComboBoxListRenderer to render an icon next to the text of the list entry.
* Also supports adding a data object to be used for more complex selection logic
*/
@AllArgsConstructor
@Getter
public class ComboBoxIconEntry
{
private Icon icon;
private String text;
@Nullable
private Object data;
}

View File

@@ -30,6 +30,7 @@ import javax.swing.JLabel;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.ListCellRenderer; import javax.swing.ListCellRenderer;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.Setter;
import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.ColorScheme;
import net.runelite.client.util.Text; import net.runelite.client.util.Text;
@@ -41,6 +42,8 @@ import net.runelite.client.util.Text;
*/ */
public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer
{ {
@Setter
private String defaultText = "Select an option...";
@Override @Override
public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus) public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
@@ -57,12 +60,24 @@ public final class ComboBoxListRenderer extends JLabel implements ListCellRender
} }
setBorder(new EmptyBorder(5, 5, 5, 0)); setBorder(new EmptyBorder(5, 5, 5, 0));
setIcon(null);
String text; String text;
if (o instanceof Enum) // If using setSelectedItem(null) or setSelectedIndex(-1) show default text until a selection is made
if (index == -1 && o == null)
{
text = defaultText;
}
else if (o instanceof Enum)
{ {
text = Text.titleCase((Enum) o); text = Text.titleCase((Enum) o);
} }
else if (o instanceof ComboBoxIconEntry)
{
ComboBoxIconEntry e = (ComboBoxIconEntry) o;
text = e.getText();
setIcon(e.getIcon());
}
else else
{ {
text = o.toString(); text = o.toString();

View File

@@ -118,7 +118,7 @@ public class GameEventManager
if (itemContainer != null) if (itemContainer != null)
{ {
eventBus.post(new ItemContainerChanged(itemContainer)); eventBus.post(new ItemContainerChanged(inventory.getId(), itemContainer));
} }
} }

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2018 raiyni <https://github.com/raiyni>
* 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.util;
import com.google.common.collect.ImmutableSet;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import static net.runelite.api.ItemID.*;
public enum Graceful
{
// TODO: It would be nice if we have the IDs for just the equipped variants of the Graceful set items.
HOOD(
GRACEFUL_HOOD_11851, GRACEFUL_HOOD_13579, GRACEFUL_HOOD_13580, GRACEFUL_HOOD_13591, GRACEFUL_HOOD_13592,
GRACEFUL_HOOD_13603, GRACEFUL_HOOD_13604, GRACEFUL_HOOD_13615, GRACEFUL_HOOD_13616, GRACEFUL_HOOD_13627,
GRACEFUL_HOOD_13628, GRACEFUL_HOOD_13667, GRACEFUL_HOOD_13668, GRACEFUL_HOOD_21061, GRACEFUL_HOOD_21063
),
TOP(
GRACEFUL_TOP_11855, GRACEFUL_TOP_13583, GRACEFUL_TOP_13584, GRACEFUL_TOP_13595, GRACEFUL_TOP_13596,
GRACEFUL_TOP_13607, GRACEFUL_TOP_13608, GRACEFUL_TOP_13619, GRACEFUL_TOP_13620, GRACEFUL_TOP_13631,
GRACEFUL_TOP_13632, GRACEFUL_TOP_13671, GRACEFUL_TOP_13672, GRACEFUL_TOP_21067, GRACEFUL_TOP_21069
),
LEGS(
GRACEFUL_LEGS_11857, GRACEFUL_LEGS_13585, GRACEFUL_LEGS_13586, GRACEFUL_LEGS_13597, GRACEFUL_LEGS_13598,
GRACEFUL_LEGS_13609, GRACEFUL_LEGS_13610, GRACEFUL_LEGS_13621, GRACEFUL_LEGS_13622, GRACEFUL_LEGS_13633,
GRACEFUL_LEGS_13634, GRACEFUL_LEGS_13673, GRACEFUL_LEGS_13674, GRACEFUL_LEGS_21070, GRACEFUL_LEGS_21072
),
GLOVES(
GRACEFUL_GLOVES_11859, GRACEFUL_GLOVES_13587, GRACEFUL_GLOVES_13588, GRACEFUL_GLOVES_13599, GRACEFUL_GLOVES_13600,
GRACEFUL_GLOVES_13611, GRACEFUL_GLOVES_13612, GRACEFUL_GLOVES_13623, GRACEFUL_GLOVES_13624, GRACEFUL_GLOVES_13635,
GRACEFUL_GLOVES_13636, GRACEFUL_GLOVES_13675, GRACEFUL_GLOVES_13676, GRACEFUL_GLOVES_21073, GRACEFUL_GLOVES_21075
),
BOOTS(
GRACEFUL_BOOTS_11861, GRACEFUL_BOOTS_13589, GRACEFUL_BOOTS_13590, GRACEFUL_BOOTS_13601, GRACEFUL_BOOTS_13602,
GRACEFUL_BOOTS_13613, GRACEFUL_BOOTS_13614, GRACEFUL_BOOTS_13625, GRACEFUL_BOOTS_13626, GRACEFUL_BOOTS_13637,
GRACEFUL_BOOTS_13638, GRACEFUL_BOOTS_13677, GRACEFUL_BOOTS_13678, GRACEFUL_BOOTS_21076, GRACEFUL_BOOTS_21078
),
// Agility skill capes and the non-cosmetic Max capes also count for the Graceful set effect
CAPE(
GRACEFUL_CAPE_11853, GRACEFUL_CAPE_13581, GRACEFUL_CAPE_13582, GRACEFUL_CAPE_13593, GRACEFUL_CAPE_13594,
GRACEFUL_CAPE_13605, GRACEFUL_CAPE_13606, GRACEFUL_CAPE_13617, GRACEFUL_CAPE_13618, GRACEFUL_CAPE_13629,
GRACEFUL_CAPE_13630, GRACEFUL_CAPE_13669, GRACEFUL_CAPE_13670, GRACEFUL_CAPE_21064, GRACEFUL_CAPE_21066,
AGILITY_CAPE, AGILITY_CAPET, MAX_CAPE
);
private final ImmutableSet<Integer> ids;
Graceful(Integer... ids)
{
this.ids = ImmutableSet.copyOf(ids);
}
public static boolean hasFullSet(final ItemContainer equipment)
{
if (equipment == null)
{
return false;
}
final Item[] items = equipment.getItems();
if (equipment == null || items.length <= EquipmentInventorySlot.BOOTS.getSlotIdx())
{
return false;
}
return HOOD.ids.contains(items[EquipmentInventorySlot.HEAD.getSlotIdx()].getId())
&& TOP.ids.contains(items[EquipmentInventorySlot.BODY.getSlotIdx()].getId())
&& LEGS.ids.contains(items[EquipmentInventorySlot.LEGS.getSlotIdx()].getId())
&& GLOVES.ids.contains(items[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId())
&& BOOTS.ids.contains(items[EquipmentInventorySlot.BOOTS.getSlotIdx()].getId())
&& CAPE.ids.contains(items[EquipmentInventorySlot.CAPE.getSlotIdx()].getId());
}
}

View File

@@ -30,7 +30,7 @@ import com.sun.jna.platform.win32.WinDef;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
class IcmpEchoReply extends Structure public class IcmpEchoReply extends Structure
{ {
private static final int IP_OPTION_INFO_SIZE = 1 + 1 + 1 + 1 + (Pointer.SIZE == 8 ? 12 : 4); // on 64bit vms add 4 byte padding private static final int IP_OPTION_INFO_SIZE = 1 + 1 + 1 + 1 + (Pointer.SIZE == 8 ? 12 : 4); // on 64bit vms add 4 byte padding
public static final int SIZE = 4 + 4 + 4 + 2 + 2 + Pointer.SIZE + IP_OPTION_INFO_SIZE; public static final int SIZE = 4 + 4 + 4 + 2 + 2 + Pointer.SIZE + IP_OPTION_INFO_SIZE;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,616 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.itemskeptondeath;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
import static net.runelite.client.plugins.itemskeptondeath.ItemsKeptOnDeathPlugin.DeathItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ItemsKeptOnDeathPluginTest
{
@Mock
@Bind
private Client client;
@Mock
@Bind
private ItemManager itemManager;
@Inject
private ItemsKeptOnDeathPlugin plugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
resetBuffs();
}
private void resetBuffs()
{
plugin.isSkulled = false;
plugin.protectingItem = false;
plugin.wildyLevel = -1;
}
// Mocks an item and the necessary itemManager functions for it
private Item mItem(final int id, final int qty, final String name, final boolean tradeable, final int price)
{
// Mock Item Composition and necessary ItemManager methods for this item
ItemDefinition c = mock(ItemDefinition.class);
when(c.getId())
.thenReturn(id);
when(c.getName())
.thenReturn(name);
when(c.isTradeable())
.thenReturn(tradeable);
when(c.getPrice())
.thenReturn(price);
if (!tradeable)
{
when(c.getNote()).thenReturn(-1);
when(c.getLinkedNoteId()).thenReturn(-1);
}
when(itemManager.getItemDefinition(id)).thenReturn(c);
when(itemManager.canonicalize(id)).thenReturn(id);
when(itemManager.getItemPrice(id, true)).thenReturn(price);
return mockItem(id, qty);
}
// Creates a mocked item
private Item mockItem(final int id, final int qty)
{
Item item = mock(Item.class);
when(item.getId()).thenReturn(id);
when(item.getQuantity()).thenReturn(qty);
return item;
}
@Test
public void deathPriceTestRegularItems()
{
final Item acs = mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495);
assertEquals(27837495, plugin.getDeathPrice(acs));
final Item karambwan = mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608);
assertEquals(608, plugin.getDeathPrice(karambwan));
final Item defender = mItem(ItemID.RUNE_DEFENDER, 1, "Rune defender", false, 35000);
assertEquals(35000, plugin.getDeathPrice(defender));
}
@Test
public void deathPriceTestItemMapping()
{
mItem(ItemID.OCCULT_NECKLACE, 1, "Occult necklace", true, 1000000);
mItem(ItemID.OCCULT_ORNAMENT_KIT, 1, "Occult ornament kit", true, 3000000);
final Item occult = mItem(ItemID.OCCULT_NECKLACE_OR, 1, "Occult necklace (or)", false, 0);
assertEquals(4000000, plugin.getDeathPrice(occult));
mItem(ItemID.BLACK_MASK, 1, "Black mask", true, 1000000);
final Item blackMask8 = mItem(ItemID.BLACK_MASK_8, 1, "Black mask (8)", false, 0);
assertEquals(1000000, plugin.getDeathPrice(blackMask8));
final Item slayerHelm = mItem(ItemID.SLAYER_HELMET, 1, "Slayer helmet", false, 0);
assertEquals(1000000, plugin.getDeathPrice(slayerHelm));
}
@Test
public void deathPriceTestFixedPriceItems()
{
mItem(ItemID.KARILS_COIF_0, 1, "Karil's coif 0", true, 35000);
final Item coif = mItem(ItemID.KARILS_COIF_100, 1, "Karil's coif 100", false, 0);
final int coifOffset = FixedPriceItem.KARILS_COIF_100.getOffset();
assertEquals(35000 + coifOffset, plugin.getDeathPrice(coif));
mItem(ItemID.AHRIMS_ROBETOP_0, 1, "Ahrim's robetop 0", true, 2500000);
final Item robetop = mItem(ItemID.AHRIMS_ROBETOP_25, 1, "Ahrim's robetop 100", false, 0);
final int robetopOffset = FixedPriceItem.AHRIMS_ROBETOP_25.getOffset();
assertEquals(2500000 + robetopOffset, plugin.getDeathPrice(robetop));
mItem(ItemID.AMULET_OF_GLORY, 1, "Amulet of glory", true, 13000);
final Item glory = mItem(ItemID.AMULET_OF_GLORY3, 1, "Amulet of glory(3)", true, 0);
final int gloryOffset = FixedPriceItem.AMULET_OF_GLORY3.getOffset();
assertEquals(13000 + gloryOffset, plugin.getDeathPrice(glory));
mItem(ItemID.COMBAT_BRACELET, 1, "Combat bracelet", true, 13500);
final Item brace = mItem(ItemID.COMBAT_BRACELET1, 1, "Combat bracelet(1)", true, 0);
final int braceletOffset = FixedPriceItem.COMBAT_BRACELET1.getOffset();
assertEquals(13500 + braceletOffset, plugin.getDeathPrice(brace));
}
@Test
public void deathPriceTestDynamicPriceItems()
{
final Item rod8 = mItem(ItemID.RING_OF_DUELING8, 1, "Ring of dueling(8)", true, 725);
final Item rod3 = mItem(ItemID.RING_OF_DUELING3, 1, "Ring of dueling(3)", true, 0);
final Item rod1 = mItem(ItemID.RING_OF_DUELING1, 1, "Ring of dueling(1)", true, 0);
// Dynamic price items
final int rodPrice = 725 / 8;
assertEquals(rodPrice, plugin.getDeathPrice(rod1));
assertEquals(725, plugin.getDeathPrice(rod8));
assertEquals(rodPrice * 3, plugin.getDeathPrice(rod3));
final Item nop5 = mItem(ItemID.NECKLACE_OF_PASSAGE5, 1, "Necklace of passage(5)", true, 1250);
final Item nop4 = mItem(ItemID.NECKLACE_OF_PASSAGE4, 1, "Necklace of passage(4)", true, 0);
final Item nop2 = mItem(ItemID.NECKLACE_OF_PASSAGE2, 1, "Necklace of passage(2)", true, 0);
final int nopPrice = 1250 / 5;
assertEquals(nopPrice * 2, plugin.getDeathPrice(nop2));
assertEquals(nopPrice * 4, plugin.getDeathPrice(nop4));
assertEquals(1250, plugin.getDeathPrice(nop5));
}
private Item[] getFourExpensiveItems()
{
return new Item[]
{
mItem(ItemID.TWISTED_BOW, 1, "Twister bow", true, Integer.MAX_VALUE),
mItem(ItemID.SCYTHE_OF_VITUR, 1, "Scythe of vitur", true, Integer.MAX_VALUE),
mItem(ItemID.ELYSIAN_SPIRIT_SHIELD, 1, "Elysian spirit shield", true, 800000000),
mItem(ItemID.ARCANE_SPIRIT_SHIELD, 1, "Arcane spirit shield", true, 250000000)
};
}
@Test
public void alwaysLostTestRunePouch()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.RUNE_POUCH, 1, "Rune pouch", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertFalse(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestRunePouchWildy()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.RUNE_POUCH, 1, "Rune pouch", false, 1)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestLootBag()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.LOOTING_BAG, 1, "Looting bag", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestLootBagWildy()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.LOOTING_BAG, 1, "Looting bag", false, 1)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
private Item[] getClueBoxTestInventory()
{
return new Item[]
{
mItem(ItemID.BLACK_DHIDE_BODY, 1, "Black d'hide body", true, 7552),
mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495),
mItem(ItemID.PEGASIAN_BOOTS, 1, "Pegasian boots", true, 30542187),
mItem(ItemID.DRAGON_SCIMITAR, 1, "Dragon scimitar", true, 63123),
mItem(ItemID.HELM_OF_NEITIZNOT, 1, "Helm of neitiznot", true, 45519),
mItem(ItemID.RUNE_DEFENDER, 1, "Rune defender", false, 35000),
mItem(ItemID.SPADE, 1, "Spade", true, 104),
mItem(ItemID.CLUE_SCROLL_EASY, 1, "Clue scroll (easy)", false, 50),
mItem(ItemID.CLUE_BOX, 1, "Clue box", false, 50),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.LAW_RUNE, 200, "Law rune", true, 212),
mItem(ItemID.DUST_RUNE, 200, "Dust rune", true, 3),
mItem(ItemID.CLUE_SCROLL_MASTER, 1, "Clue scroll (master)", false, 50),
mItem(ItemID.CLUELESS_SCROLL, 1, "Clueless scroll", false, 50),
};
}
@Test
public void isClueBoxableTest()
{
getClueBoxTestInventory();
mItem(ItemID.REWARD_CASKET_EASY, 1, "Reward casket (easy)", false, 50);
assertTrue(plugin.isClueBoxable(ItemID.CLUE_SCROLL_EASY));
assertTrue(plugin.isClueBoxable(ItemID.CLUE_SCROLL_MASTER));
assertTrue(plugin.isClueBoxable(ItemID.REWARD_CASKET_EASY));
assertFalse(plugin.isClueBoxable(ItemID.CLUELESS_SCROLL));
assertFalse(plugin.isClueBoxable(ItemID.LAW_RUNE));
assertFalse(plugin.isClueBoxable(ItemID.SPADE));
}
@Test
public void clueBoxTestDefault()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1),
new ItemStack(ItemID.CLUE_SCROLL_EASY, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1),
new ItemStack(ItemID.CLUELESS_SCROLL, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void clueBoxTestDeepWildy()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestDeepWildyProtectItem()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
plugin.protectingItem = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.HELM_OF_NEITIZNOT, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1) // Clue box
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestDeepWildySkulled()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
plugin.isSkulled = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Collections.singletonList(
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals(lost.size(), (inv.length + equip.length) - keptOffset);
}
@Test
public void clueBoxTestLowWildy()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals(lost.size(), (inv.length + equip.length) - keptOffset);
}
@Test
public void clueBoxTestLowWildyProtectItem()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
plugin.protectingItem = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.HELM_OF_NEITIZNOT, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestLowWildySkulled()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
plugin.isSkulled = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
private Item[] getClueBoxCasketTestInventory()
{
// Reward caskets can stack but the clue box should only protect one
return new Item[]
{
mItem(ItemID.BLACK_DHIDE_BODY, 1, "Black d'hide body", true, 7552),
mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495),
mItem(ItemID.PEGASIAN_BOOTS, 1, "Pegasian boots", true, 30542187),
mItem(ItemID.DRAGON_SCIMITAR, 1, "Dragon scimitar", true, 63123),
mItem(ItemID.SPADE, 1, "Spade", true, 104),
mItem(ItemID.CLUE_SCROLL_EASY, 1, "Clue scroll (easy)", false, 50),
mItem(ItemID.REWARD_CASKET_EASY, 20, "Reward casket (easy)", false, 50),
mItem(ItemID.CLUE_BOX, 1, "Clue box", false, 50),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.LAW_RUNE, 200, "Law rune", true, 212),
mItem(ItemID.DUST_RUNE, 200, "Dust rune", true, 3),
};
}
@Test
public void clueBoxTestCasketProtect()
{
final Item[] inv = getClueBoxCasketTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.REWARD_CASKET_EASY, 1) // Clue box
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size() - 1; // We are still losing some reward caskets.
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
private Item[] getFullGracefulItems()
{
return new Item[]
{
mItem(ItemID.GRACEFUL_HOOD, 1, "Graceful hood", false, 35),
mItem(ItemID.GRACEFUL_CAPE, 1, "Graceful cape", false, 40),
mItem(ItemID.GRACEFUL_TOP, 1, "Graceful top", false, 55),
mItem(ItemID.GRACEFUL_LEGS, 1, "Graceful legs", false, 60),
mItem(ItemID.GRACEFUL_BOOTS, 1, "Graceful boots", false, 40),
mItem(ItemID.GRACEFUL_GLOVES, 1, "Graceful gloves", false, 30),
};
}
@Test
public void gracefulValueTest()
{
final Item[] inv = getFullGracefulItems();
final Item[] equip = new Item[]
{
mItem(ItemID.AMULET_OF_GLORY6, 1, "Amulet of glory (6)", true, 20000)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.AMULET_OF_GLORY6, 1),
new ItemStack(ItemID.GRACEFUL_CAPE, 1),
new ItemStack(ItemID.GRACEFUL_TOP, 1),
new ItemStack(ItemID.GRACEFUL_LEGS, 1),
new ItemStack(ItemID.GRACEFUL_BOOTS, 1),
new ItemStack(ItemID.GRACEFUL_HOOD, 1),
new ItemStack(ItemID.GRACEFUL_GLOVES, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void gracefulValueTestWildy()
{
final Item[] inv = getFullGracefulItems();
final Item[] equip = new Item[]
{
mItem(ItemID.AMULET_OF_GLORY6, 1, "Amulet of glory (6)", true, 20000)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.AMULET_OF_GLORY6, 1),
new ItemStack(ItemID.GRACEFUL_CAPE, 1),
new ItemStack(ItemID.GRACEFUL_TOP, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void lostIfNotProtectedTestLost()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.SHADOW_SWORD, 1, "Shadow sword", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> lost = deathItems.getLostItems();
assertTrue(lost.contains(new ItemStack(ItemID.SHADOW_SWORD, 1)));
}
@Test
public void lostIfNotProtectedTestKept()
{
final Item[] inv = new Item[]
{
mItem(ItemID.SHADOW_SWORD, 1, "Shadow sword", false, 1)
};
final Item[] equip = new Item[0];
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
assertTrue(kept.contains(new ItemStack(ItemID.SHADOW_SWORD, 1)));
}
}

View File

@@ -162,7 +162,7 @@ public class MotherlodePluginTest
when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory); when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory);
// Trigger comparison // Trigger comparison
motherlodePlugin.onItemContainerChanged(new ItemContainerChanged(inventory)); motherlodePlugin.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), inventory));
verify(motherlodeSession).updateOreFound(ItemID.RUNITE_ORE, 1); verify(motherlodeSession).updateOreFound(ItemID.RUNITE_ORE, 1);
verify(motherlodeSession).updateOreFound(ItemID.GOLDEN_NUGGET, 4); verify(motherlodeSession).updateOreFound(ItemID.GOLDEN_NUGGET, 4);

View File

@@ -163,6 +163,9 @@ public abstract class RSClientMixin implements RSClient
@Inject @Inject
private static boolean interpolateObjectAnimations; private static boolean interpolateObjectAnimations;
@Inject
private static boolean interpolateWidgetAnimations;
@Inject @Inject
private static RSPlayer[] oldPlayers = new RSPlayer[2048]; private static RSPlayer[] oldPlayers = new RSPlayer[2048];
@@ -307,6 +310,20 @@ public abstract class RSClientMixin implements RSClient
interpolateObjectAnimations = interpolate; interpolateObjectAnimations = interpolate;
} }
@Inject
@Override
public boolean isInterpolateWidgetAnimations()
{
return interpolateWidgetAnimations;
}
@Inject
@Override
public void setInterpolateWidgetAnimations(boolean interpolate)
{
interpolateWidgetAnimations = interpolate;
}
@Inject @Inject
@Override @Override
public void setInventoryDragDelay(int delay) public void setInventoryDragDelay(int delay)

View File

@@ -24,11 +24,13 @@
*/ */
package net.runelite.mixins; package net.runelite.mixins;
import net.runelite.api.InventoryID;
import net.runelite.api.Item; import net.runelite.api.Item;
import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.mixins.FieldHook; import net.runelite.api.mixins.Copy;
import net.runelite.api.mixins.Inject; import net.runelite.api.mixins.Inject;
import net.runelite.api.mixins.Mixin; import net.runelite.api.mixins.Mixin;
import net.runelite.api.mixins.Replace;
import net.runelite.api.mixins.Shadow; import net.runelite.api.mixins.Shadow;
import net.runelite.rs.api.RSClient; import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSGroundItem; import net.runelite.rs.api.RSGroundItem;
@@ -41,7 +43,7 @@ public abstract class RSItemContainerMixin implements RSItemContainer
private static RSClient client; private static RSClient client;
@Inject @Inject
private int rl$lastCycle; static private int rl$lastCycle;
@Inject @Inject
@Override @Override
@@ -62,21 +64,27 @@ public abstract class RSItemContainerMixin implements RSItemContainer
return items; return items;
} }
@FieldHook("quantities") @Copy("itemContainerSetItem")
@Inject static void rs$itemContainerSetItem(int itemContainerId, int index, int itemId, int itemQuantity)
public void stackSizesChanged(int idx)
{ {
}
@Replace("itemContainerSetItem")
static void rl$itemContainerSetItem(int itemContainerId, int index, int itemId, int itemQuantity)
{
rs$itemContainerSetItem(itemContainerId, index, itemId, itemQuantity);
int cycle = client.getGameCycle(); int cycle = client.getGameCycle();
if (rl$lastCycle == cycle) if (rl$lastCycle == cycle)
{ {
// Limit item container updates to one per cycle // Limit item container updates to one per cycle
// No need to repeatedly update. The game just needs to know that containers changed once per cycle
return; return;
} }
rl$lastCycle = cycle; rl$lastCycle = cycle;
ItemContainerChanged event = new ItemContainerChanged(itemContainerId, client.getItemContainer(InventoryID.getValue(itemContainerId)));
ItemContainerChanged event = new ItemContainerChanged(this);
client.getCallbacks().postDeferred(event); client.getCallbacks().postDeferred(event);
} }
} }

View File

@@ -15,10 +15,10 @@ public abstract class RSSequenceDefinitionMixin implements RSSequenceDefinition
@Shadow("client") @Shadow("client")
private static RSClient client; private static RSClient client;
@Copy("animateSequence2") @Copy("applyTransformations")
public abstract RSModel rs$applyTransformations(RSModel model, int actionFrame, RSSequenceDefinition poseSeq, int poseFrame); public abstract RSModel rs$applyTransformations(RSModel model, int actionFrame, RSSequenceDefinition poseSeq, int poseFrame);
@Replace("animateSequence2") @Replace("applyTransformations")
public RSModel rl$applyTransformations(RSModel model, int actionFrame, RSSequenceDefinition poseSeq, int poseFrame) public RSModel rl$applyTransformations(RSModel model, int actionFrame, RSSequenceDefinition poseSeq, int poseFrame)
{ {
// reset frame ids because we're not interpolating this // reset frame ids because we're not interpolating this
@@ -35,185 +35,253 @@ public abstract class RSSequenceDefinitionMixin implements RSSequenceDefinition
return rs$applyTransformations(model, actionFrame, poseSeq, poseFrame); return rs$applyTransformations(model, actionFrame, poseSeq, poseFrame);
} }
@Copy("animateSequence") @Copy("transformActorModel")
public abstract RSModel rs$transformActorModel(RSModel model, int frameIdx); public abstract RSModel rs$transformActorModel(RSModel model, int frameIdx);
@Replace("animateSequence") @Replace("transformActorModel")
public RSModel rl$transformActorModel(RSModel model, int frame) public RSModel rl$transformActorModel(RSModel model, int frame)
{ {
// check if the frame has been modified // check if the frame has not been modified
if (frame < 0) if (frame >= 0)
{
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
// not sure what toSharedModel does but it is needed
return model.toSharedModel(true);
}
else
{
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
return animatedModel;
}
}
else
{ {
return rs$transformActorModel(model, frame); return rs$transformActorModel(model, frame);
} }
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
// not sure what toSharedModel does but it is needed
return model.toSharedModel(true);
}
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
return animatedModel;
} }
@Copy("animateObject") @Copy("transformObjectModel")
public abstract RSModel rs$transformObjectModel(RSModel model, int frame, int rotation); public abstract RSModel rs$transformObjectModel(RSModel model, int frame, int rotation);
@Replace("animateObject") @Replace("transformObjectModel")
public RSModel rl$transformObjectModel(RSModel model, int frame, int rotation) public RSModel rl$transformObjectModel(RSModel model, int frame, int rotation)
{ {
// check if the frame has been modified // check if the frame has not been modified
if (frame < 0) if (frame >= 0)
{
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
return model.toSharedModel(true);
}
else
{
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing());
// reset rotation before animating
rotation &= 3;
if (rotation == 1)
{
animatedModel.rotateY270Ccw();
}
else if (rotation == 2)
{
animatedModel.rotateY180Ccw();
}
else if (rotation == 3)
{
animatedModel.rotateY90Ccw();
}
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
// reapply rotation after animating
if (rotation == 1)
{
animatedModel.rotateY90Ccw();
}
else if (rotation == 2)
{
animatedModel.rotateY180Ccw();
}
else if (rotation == 3)
{
animatedModel.rotateY270Ccw();
}
return animatedModel;
}
}
else
{ {
return rs$transformObjectModel(model, frame, rotation); return rs$transformObjectModel(model, frame, rotation);
} }
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
return model.toSharedModel(true);
}
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing());
// reset rotation before animating
rotation &= 3;
if (rotation == 1)
{
animatedModel.rotateY270Ccw();
}
else if (rotation == 2)
{
animatedModel.rotateY180Ccw();
}
else if (rotation == 3)
{
animatedModel.rotateY90Ccw();
}
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
// reapply rotation after animating
if (rotation == 1)
{
animatedModel.rotateY90Ccw();
}
else if (rotation == 2)
{
animatedModel.rotateY180Ccw();
}
else if (rotation == 3)
{
animatedModel.rotateY270Ccw();
}
return animatedModel;
} }
@Copy("animateSpotAnimation") @Copy("transformSpotAnimationModel")
public abstract RSModel rs$transformSpotAnimModel(RSModel model, int frame); public abstract RSModel rs$transformSpotAnimationModel(RSModel model, int frame);
@Replace("animateSpotAnimation") @Replace("transformSpotAnimationModel")
public RSModel rl$transformSpotAnimModel(RSModel model, int frame) public RSModel rl$transformSpotAnimationModel(RSModel model, int frame)
{ {
// check if the frame has been modified // check if the frame has not been modified
if (frame < 0) if (frame >= 0)
{ {
// remove flag to check if the frame has been modified return rs$transformSpotAnimationModel(model, frame);
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
return model.toSharedSpotAnimModel(true);
}
else
{
RSModel animatedModel = model.toSharedSpotAnimModel(!frames.getFrames()[frameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
return animatedModel;
}
} }
else
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{ {
return rs$transformSpotAnimModel(model, frame); // dont interpolate last frame
nextFrame = -1;
} }
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
return model.toSharedSpotAnimModel(true);
}
RSModel animatedModel = model.toSharedSpotAnimModel(!frames.getFrames()[frameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
return animatedModel;
}
@Copy("transformWidgetModel")
public abstract RSModel rs$transformWidgetModel(RSModel model, int frame);
@Replace("transformWidgetModel")
public RSModel rl$transformWidgetModel(RSModel model, int frame)
{
// check if the frame has not been modified
if (frame >= 0)
{
return rs$transformWidgetModel(model, frame);
}
// remove flag to check if the frame has been modified
int packed = frame ^ Integer.MIN_VALUE;
int interval = packed >> 16;
frame = packed & 0xFFFF;
int nextFrame = frame + 1;
if (nextFrame >= getFrameIDs().length)
{
// dont interpolate last frame
nextFrame = -1;
}
int[] frameIds = getFrameIDs();
int frameId = frameIds[frame];
RSFrames frames = client.getFrames(frameId >> 16);
int frameIdx = frameId & 0xFFFF;
int nextFrameIdx = -1;
RSFrames nextFrames = null;
if (nextFrame != -1)
{
int nextFrameId = frameIds[nextFrame];
nextFrames = client.getFrames(nextFrameId >> 16);
nextFrameIdx = nextFrameId & 0xFFFF;
}
if (frames == null)
{
return model.toSharedModel(true);
}
RSFrames chatFrames = null;
int chatFrameIdx = 0;
if (getChatFrameIds() != null && frame < getChatFrameIds().length)
{
int chatFrameId = getChatFrameIds()[frame];
chatFrames = client.getFrames(chatFrameId >> 16);
chatFrameIdx = chatFrameId & 0xFFFF;
}
if (chatFrames != null && chatFrameIdx != 0xFFFF)
{
RSFrames nextChatFrames = null;
int nextChatFrameIdx = -1;
if (nextFrame != -1 && nextFrame < getChatFrameIds().length)
{
int chatFrameId = getChatFrameIds()[nextFrame];
nextChatFrames = client.getFrames(chatFrameId >> 16);
nextChatFrameIdx = chatFrameId & 0xFFFF;
}
// not sure if this can even happen but the client checks for this so to be safe
if (nextChatFrameIdx == 0xFFFF)
{
nextChatFrames = null;
}
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing()
& !chatFrames.getFrames()[chatFrameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
animatedModel.interpolateFrames(chatFrames, chatFrameIdx, nextChatFrames, nextChatFrameIdx,
interval, getFrameLenths()[frame]);
return animatedModel;
}
RSModel animatedModel = model.toSharedModel(!frames.getFrames()[frameIdx].isShowing());
animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval,
getFrameLenths()[frame]);
return animatedModel;
} }
} }

View File

@@ -30,6 +30,8 @@ import net.runelite.api.Point;
import net.runelite.api.WidgetNode; import net.runelite.api.WidgetNode;
import net.runelite.api.events.WidgetHiddenChanged; import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.events.WidgetPositioned; import net.runelite.api.events.WidgetPositioned;
import net.runelite.api.mixins.Copy;
import net.runelite.api.mixins.Replace;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD; import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
@@ -44,8 +46,11 @@ import net.runelite.api.mixins.Inject;
import net.runelite.api.mixins.Mixin; import net.runelite.api.mixins.Mixin;
import net.runelite.api.mixins.Shadow; import net.runelite.api.mixins.Shadow;
import net.runelite.rs.api.RSClient; import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSModel;
import net.runelite.rs.api.RSNode; import net.runelite.rs.api.RSNode;
import net.runelite.rs.api.RSNodeHashTable; import net.runelite.rs.api.RSNodeHashTable;
import net.runelite.rs.api.RSPlayerAppearance;
import net.runelite.rs.api.RSSequenceDefinition;
import net.runelite.rs.api.RSWidget; import net.runelite.rs.api.RSWidget;
@Mixin(RSWidget.class) @Mixin(RSWidget.class)
@@ -581,4 +586,17 @@ public abstract class RSWidgetMixin implements RSWidget
Arrays.fill(getChildren(), null); Arrays.fill(getChildren(), null);
} }
} }
@Copy("getModel")
public abstract RSModel rs$getModel(RSSequenceDefinition sequence, int frame, boolean alternate, RSPlayerAppearance playerComposition);
@Replace("getModel")
public RSModel rl$getModel(RSSequenceDefinition sequence, int frame, boolean alternate, RSPlayerAppearance playerComposition)
{
if (frame != -1 && client.isInterpolateWidgetAnimations())
{
frame = frame | getModelFrameCycle() << 16 | Integer.MIN_VALUE;
}
return rs$getModel(sequence, frame, alternate, playerComposition);
}
} }

View File

@@ -24,4 +24,7 @@ public interface RSSequenceDefinition
@Import("frameLengths") @Import("frameLengths")
int[] getFrameLenths(); int[] getFrameLenths();
@Import("chatFrameIds")
int[] getChatFrameIds();
} }

View File

@@ -475,4 +475,10 @@ public interface RSWidget extends Widget
@Import("noScrollThrough") @Import("noScrollThrough")
@Override @Override
void setNoScrollThrough(boolean noScrollThrough); void setNoScrollThrough(boolean noScrollThrough);
@Import("modelFrame")
int getModelFrame();
@Import("modelFrameCycle")
int getModelFrameCycle();
} }

View File

@@ -424,11 +424,11 @@ public class NPCDefinition extends DualNode {
Model var10; Model var10;
if (var1 != null && var3 != null) { if (var1 != null && var3 != null) {
var10 = var1.animateSequence2(var5, var2, var3, var4); var10 = var1.applyTransformations(var5, var2, var3, var4);
} else if (var1 != null) { } else if (var1 != null) {
var10 = var1.animateSequence(var5, var2); var10 = var1.transformActorModel(var5, var2);
} else if (var3 != null) { } else if (var3 != null) {
var10 = var3.animateSequence(var5, var4); var10 = var3.transformActorModel(var5, var4);
} else { } else {
var10 = var5.toSharedSequenceModel(true); var10 = var5.toSharedSequenceModel(true);
} }

View File

@@ -662,7 +662,7 @@ public class ObjectDefinition extends DualNode {
return var11; return var11;
} else { } else {
if (var7 != null) { if (var7 != null) {
var11 = var7.animateObject(var11, var8, var2); var11 = var7.transformObjectModel(var11, var8, var2);
} else { } else {
var11 = var11.toSharedSequenceModel(true); var11 = var11.toSharedSequenceModel(true);
} }

View File

@@ -321,11 +321,11 @@ public class PlayerAppearance {
} else { } else {
Model var16; Model var16;
if (var1 != null && var3 != null) { if (var1 != null && var3 != null) {
var16 = var1.animateSequence2(var15, var2, var3, var4); var16 = var1.applyTransformations(var15, var2, var3, var4);
} else if (var1 != null) { } else if (var1 != null) {
var16 = var1.animateSequence(var15, var2); var16 = var1.transformActorModel(var15, var2);
} else { } else {
var16 = var3.animateSequence(var15, var4); var16 = var3.transformActorModel(var15, var4);
} }
return var16; return var16;

View File

@@ -38,8 +38,8 @@ public class SequenceDefinition extends DualNode {
@Export("frameIds") @Export("frameIds")
public int[] frameIds; public int[] frameIds;
@ObfuscatedName("g") @ObfuscatedName("g")
@Export("frameIds2") @Export("chatFrameIds")
int[] frameIds2; int[] chatFrameIds;
@ObfuscatedName("l") @ObfuscatedName("l")
@Export("frameLengths") @Export("frameLengths")
public int[] frameLengths; public int[] frameLengths;
@@ -179,14 +179,14 @@ public class SequenceDefinition extends DualNode {
this.field783 = var1.readUnsignedByte(); this.field783 = var1.readUnsignedByte();
} else if (var2 == 12) { } else if (var2 == 12) {
var4 = var1.readUnsignedByte(); var4 = var1.readUnsignedByte();
this.frameIds2 = new int[var4]; this.chatFrameIds = new int[var4];
for (var5 = 0; var5 < var4; ++var5) { for (var5 = 0; var5 < var4; ++var5) {
this.frameIds2[var5] = var1.readUnsignedShort(); this.chatFrameIds[var5] = var1.readUnsignedShort();
} }
for (var5 = 0; var5 < var4; ++var5) { for (var5 = 0; var5 < var4; ++var5) {
var3 = this.frameIds2; var3 = this.chatFrameIds;
var3[var5] += var1.readUnsignedShort() << 16; var3[var5] += var1.readUnsignedShort() << 16;
} }
} else if (var2 == 13) { } else if (var2 == 13) {
@@ -230,8 +230,8 @@ public class SequenceDefinition extends DualNode {
signature = "(Ldu;II)Ldu;", signature = "(Ldu;II)Ldu;",
garbageValue = "128527714" garbageValue = "128527714"
) )
@Export("animateSequence") @Export("transformActorModel")
public Model animateSequence(Model model, int frame) { public Model transformActorModel(Model model, int frame) {
frame = this.frameIds[frame]; frame = this.frameIds[frame];
Frames var3 = ItemContainer.getFrames(frame >> 16); Frames var3 = ItemContainer.getFrames(frame >> 16);
frame &= 65535; frame &= 65535;
@@ -249,8 +249,8 @@ public class SequenceDefinition extends DualNode {
signature = "(Ldu;IIB)Ldu;", signature = "(Ldu;IIB)Ldu;",
garbageValue = "-65" garbageValue = "-65"
) )
@Export("animateObject") @Export("transformObjectModel")
Model animateObject(Model model, int frame, int orientation) { Model transformObjectModel(Model model, int frame, int orientation) {
frame = this.frameIds[frame]; frame = this.frameIds[frame];
Frames var4 = ItemContainer.getFrames(frame >> 16); Frames var4 = ItemContainer.getFrames(frame >> 16);
frame &= 65535; frame &= 65535;
@@ -285,8 +285,8 @@ public class SequenceDefinition extends DualNode {
signature = "(Ldu;II)Ldu;", signature = "(Ldu;II)Ldu;",
garbageValue = "-1692496767" garbageValue = "-1692496767"
) )
@Export("animateSpotAnimation") @Export("transformSpotAnimationModel")
Model animateSpotAnimation(Model model, int frame) { Model transformSpotAnimationModel(Model model, int frame) {
frame = this.frameIds[frame]; frame = this.frameIds[frame];
Frames var3 = ItemContainer.getFrames(frame >> 16); Frames var3 = ItemContainer.getFrames(frame >> 16);
frame &= 65535; frame &= 65535;
@@ -304,13 +304,13 @@ public class SequenceDefinition extends DualNode {
signature = "(Ldu;ILjh;II)Ldu;", signature = "(Ldu;ILjh;II)Ldu;",
garbageValue = "-386360993" garbageValue = "-386360993"
) )
@Export("animateSequence2") @Export("applyTransformations")
public Model animateSequence2(Model model, int frame, SequenceDefinition sequence, int sequenceFrame) { public Model applyTransformations(Model model, int frame, SequenceDefinition sequence, int sequenceFrame) {
frame = this.frameIds[frame]; frame = this.frameIds[frame];
Frames var5 = ItemContainer.getFrames(frame >> 16); Frames var5 = ItemContainer.getFrames(frame >> 16);
frame &= 65535; frame &= 65535;
if (var5 == null) { if (var5 == null) {
return sequence.animateSequence(model, sequenceFrame); return sequence.transformActorModel(model, sequenceFrame);
} else { } else {
sequenceFrame = sequence.frameIds[sequenceFrame]; sequenceFrame = sequence.frameIds[sequenceFrame];
Frames var6 = ItemContainer.getFrames(sequenceFrame >> 16); Frames var6 = ItemContainer.getFrames(sequenceFrame >> 16);
@@ -333,8 +333,8 @@ public class SequenceDefinition extends DualNode {
signature = "(Ldu;II)Ldu;", signature = "(Ldu;II)Ldu;",
garbageValue = "-15433768" garbageValue = "-15433768"
) )
@Export("animateWidget") @Export("transformWidgetModel")
public Model animateWidget(Model model, int frame) { public Model transformWidgetModel(Model model, int frame) {
int var3 = this.frameIds[frame]; int var3 = this.frameIds[frame];
Frames var4 = ItemContainer.getFrames(var3 >> 16); Frames var4 = ItemContainer.getFrames(var3 >> 16);
var3 &= 65535; var3 &= 65535;
@@ -343,8 +343,8 @@ public class SequenceDefinition extends DualNode {
} else { } else {
Frames var5 = null; Frames var5 = null;
int var6 = 0; int var6 = 0;
if (this.frameIds2 != null && frame < this.frameIds2.length) { if (this.chatFrameIds != null && frame < this.chatFrameIds.length) {
var6 = this.frameIds2[frame]; var6 = this.chatFrameIds[frame];
var5 = ItemContainer.getFrames(var6 >> 16); var5 = ItemContainer.getFrames(var6 >> 16);
var6 &= 65535; var6 &= 65535;
} }

View File

@@ -196,7 +196,7 @@ public class SpotAnimationDefinition extends DualNode {
Model var5; Model var5;
if (this.sequence != -1 && var1 != -1) { if (this.sequence != -1 && var1 != -1) {
var5 = WorldMapAreaData.getSequenceDefinition(this.sequence).animateSpotAnimation(var2, var1); var5 = WorldMapAreaData.getSequenceDefinition(this.sequence).transformSpotAnimationModel(var2, var1);
} else { } else {
var5 = var2.toSharedSpotAnimationModel(true); var5 = var2.toSharedSpotAnimationModel(true);
} }

View File

@@ -1376,11 +1376,11 @@ public class Widget extends Node {
garbageValue = "1082545676" garbageValue = "1082545676"
) )
@Export("getModel") @Export("getModel")
public Model getModel(SequenceDefinition sequence, int frame, boolean var3, PlayerAppearance appearance) { public Model getModel(SequenceDefinition sequence, int frame, boolean alternate, PlayerAppearance appearance) {
field957 = false; field957 = false;
int var5; int var5;
int var6; int var6;
if (var3) { if (alternate) {
var5 = this.modelType2; var5 = this.modelType2;
var6 = this.modelId2; var6 = this.modelId2;
} else { } else {
@@ -1445,7 +1445,7 @@ public class Widget extends Node {
} }
if (sequence != null) { if (sequence != null) {
var7 = sequence.animateWidget(var7, frame); var7 = sequence.transformWidgetModel(var7, frame);
} }
return var7; return var7;