chore: init
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.gameval.AnimationID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public enum AnimationData
|
||||
{
|
||||
// MELEE
|
||||
MELEE_VIGGORAS_CHAINMACE(AnimationID.WILD_CAVE_CHAINMACE_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_DAGGER_SLASH(AnimationID.HUMAN_DDAGGER_LUNGE, AttackStyle.MELEE),
|
||||
MELEE_SPEAR_STAB(AnimationID.HUMAN_DSPEAR_STAB, AttackStyle.MELEE),
|
||||
MELEE_SWORD_STAB(AnimationID.HUMAN_SWORD_STAB, AttackStyle.MELEE),
|
||||
MELEE_SCIM_SLASH(AnimationID.HUMAN_SWORD_SLASH, AttackStyle.MELEE),
|
||||
|
||||
MELEE_LANCE_STAB(AnimationID.HUMAN_DHUNTER_LANCE_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_LANCE_CRUSH(AnimationID.HUMAN_DHUNTER_LANCE_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_LANCE_SLASH(AnimationID.HUMAN_DHUNTER_LANCE_SLASH, AttackStyle.MELEE),
|
||||
|
||||
MELEE_FANG_STAB(AnimationID.HUMAN_OSMUMTENS_FANG, AttackStyle.MELEE),
|
||||
MELEE_FANG_SPEC(AnimationID.OLAF2_BRINE_SABRE_SPECIAL, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
|
||||
MELEE_GENERIC_SLASH(AnimationID.HUMAN_AXE_CHOP, AttackStyle.MELEE),
|
||||
|
||||
MELEE_BATTLEAXE_SLASH(AnimationID.HUMAN_AXE_HACK, AttackStyle.MELEE),
|
||||
MELEE_MACE_STAB(AnimationID.HUMAN_BLUNT_SPIKE, AttackStyle.MELEE),
|
||||
MELEE_BATTLEAXE_CRUSH(AnimationID.HUMAN_BLUNT_POUND, AttackStyle.MELEE),
|
||||
MELEE_2H_CRUSH(AnimationID.HUMAN_DHSWORD_CHOP, AttackStyle.MELEE),
|
||||
MELEE_2H_SLASH(AnimationID.HUMAN_DHSWORD_SLASH, AttackStyle.MELEE),
|
||||
MELEE_STAFF_CRUSH_2(AnimationID.HUMAN_STAFF_PUMMEL, AttackStyle.MELEE),
|
||||
MELEE_STAFF_CRUSH_3(AnimationID.HUMAN_STAFFORB_PUMMEL, AttackStyle.MELEE),
|
||||
MELEE_PUNCH(AnimationID.HUMAN_UNARMEDPUNCH, AttackStyle.MELEE),
|
||||
MELEE_KICK(AnimationID.HUMAN_UNARMEDKICK, AttackStyle.MELEE),
|
||||
MELEE_STAFF_STAB(AnimationID.HUMAN_SPEAR_SPIKE, AttackStyle.MELEE),
|
||||
MELEE_SPEAR_CRUSH(AnimationID.HUMAN_SPEAR_LUNGE, AttackStyle.MELEE),
|
||||
MELEE_STAFF_SLASH(AnimationID.HUMAN_SCYTHE_SWEEP, AttackStyle.MELEE),
|
||||
MELEE_DLONG_SPEC(AnimationID.CLEAVE, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DRAGON_MACE_SPEC(AnimationID.SHATTER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DRAGON_DAGGER_SPEC(AnimationID.PUNCTURE, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DRAGON_WARHAMMER_SPEC(AnimationID.DRAGON_WARHAMMER_SA_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ABYSSAL_WHIP(AnimationID.SLAYER_ABYSSAL_WHIP_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_GRANITE_MAUL(AnimationID.SLAYER_GRANITE_MAUL_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_GRANITE_MAUL_SPEC(AnimationID.SLAYER_GRANITE_MAUL_SPECIAL_ATTACK, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DHAROKS_GREATAXE_CRUSH(AnimationID.BARROW_DHAROK_SLASH, AttackStyle.MELEE),
|
||||
MELEE_DHAROKS_GREATAXE_SLASH(AnimationID.BARROW_DHAROK_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_AHRIMS_STAFF_CRUSH(AnimationID.BARROWS_QUARTERSTAFF_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_OBBY_MAUL_CRUSH(AnimationID.DRAGON_PICKAXE_ANIM, AttackStyle.MELEE),
|
||||
MELEE_ABYSSAL_DAGGER_STAB(AnimationID.ABYSSAL_DAGGER_LUNGE, AttackStyle.MELEE),
|
||||
MELEE_ABYSSAL_BLUDGEON_CRUSH(AnimationID.ABYSSAL_BLUDGEON_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_ABYSSAL_BLUDGEON_SPEC(AnimationID.ABYSSAL_BLUDGEON_SPECIAL_ATTACK, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_LEAF_BLADED_BATTLEAXE_CRUSH(AnimationID.BATTLEAXE_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_INQUISITORS_MACE(AnimationID.HUMAN_INQUISITORS_MACE_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_BARRELCHEST_ANCHOR_CRUSH(AnimationID.BRAIN_PLAYER_ANCHOR_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_BARRELCHEST_ANCHOR_CRUSH_SPEC(AnimationID.BRAIN_PLAYER_ANCHOR_SPECIAL_ATTACK, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_LEAF_BLADED_BATTLEAXE_SLASH(AnimationID.GODWARS_GODSWORD_ZAMORAK_PLAYER, AttackStyle.MELEE),
|
||||
MELEE_GODSWORD_SLASH(AnimationID.DH_SWORD_UPDATE_SLASH, AttackStyle.MELEE),
|
||||
MELEE_GODSWORD_CRUSH(AnimationID.DH_SWORD_UPDATE_SMASH, AttackStyle.MELEE),
|
||||
MELEE_GODSWORD_DEFENSIVE(AnimationID.DH_SWORD_UPDATE_BLOCK, AttackStyle.MELEE),
|
||||
MELEE_RUNE_CLAWS_SPEC(AnimationID.IMPALE, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DRAGON_CLAWS_SPEC(AnimationID.HUMAN_DRAGON_CLAWS_SPEC, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_VLS_SPEC(AnimationID.HUMAN_DRAGON_SWORD_SPEC, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ELDER_MAUL(AnimationID.HUMAN_ELDER_MAUL_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_ZAMORAK_GODSWORD_SPEC(AnimationID.ZGS_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ELDER_MAUL_SPEC(AnimationID.HUMAN_ELDER_MAUL_SPEC, AttackStyle.MELEE),
|
||||
MELEE_ZAMORAK_GODSWORD_OR_SPEC(AnimationID.ZGS_SPECIAL_ORNATE_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SARADOMIN_GODSWORD_SPEC(AnimationID.SGS_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SARADOMIN_GODSWORD_OR_SPEC(AnimationID.SGS_SPECIAL_ORNATE_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_BANDOS_GODSWORD_SPEC(AnimationID.BGS_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_BANDOS_GODSWORD_OR_SPEC(AnimationID.BGS_SPECIAL_ORNATE_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ARMADYL_GODSWORD_SPEC(AnimationID.AGS_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ARMADYL_GODSWORD_OR_SPEC(AnimationID.AGS_SPECIAL_ORNATE_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SCYTHE(AnimationID.SCYTHE_OF_VITUR_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_GHAZI_RAPIER_STAB(AnimationID.GHRAZI_RAPIER_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_ANCIENT_GODSWORD_SPEC(AnimationID.NGS_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_CRYSTAL_HALBERD_SPEC(AnimationID.DRAGON_HALBERD_SPECIAL_ATTACK, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SOULREAPER_AXE(AnimationID.ANCIENT_AXE_CRUSH, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SOULREAPER_AXE_SPEC(AnimationID.ANCIENT_AXE_SPECIAL, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_GUTHANS_LUNGE(AnimationID.BARROWS_WAR_SPEAR_STAB, AttackStyle.MELEE),
|
||||
MELEE_GUTHANS_SWIPE(AnimationID.BARROWS_WAR_SPEAR_SLASH, AttackStyle.MELEE),
|
||||
MELEE_GUTHANS_POUNDMA(AnimationID.BARROWS_WAR_SPEAR_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_TORAG_HAMMERS(AnimationID.BARROW_TORAG_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_VERACS_FLAIL(AnimationID.BARROW_GUTHAN_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_BLISTERWOOD_FLAIL_CRUSH(AnimationID.IVANDIS_FLAIL_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_BONE_DAGGER_SPEC(AnimationID.DTTD_PLAYER_STAB_BONE_DAGGER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DUAL_MACUAHUITL(AnimationID.PMOON_MACUAHUITL_CRUSH, AttackStyle.MELEE),
|
||||
MELEE_BLUE_MOON_SPEAR_SPEC(AnimationID.HUMAN_ZAMORAKSPEAR_LUNGE, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_BLUE_MOON_SPEAR(AnimationID.HUMAN_ZAMORAKSPEAR_STAB, AttackStyle.MELEE),
|
||||
MELEE_DHINS(AnimationID.HUMAN_DINHS_BULWARK_BASH, AttackStyle.MELEE),
|
||||
MELEE_URSINE_CHAINMACE_SPEC(AnimationID.HUMAN_SPECIAL02_URSINE, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ANCIENT_MACE_SPEC(AnimationID.SLICE_PLAYER_MACE_SPECIAL_ATTACK, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_DSCIM_SPEC(AnimationID.SP_ATTACK_DRAGON_SCIMITAR, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_D2H_SPEC(AnimationID.DRAGON_TWO_HANDED_SWORD, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_ARCLIGHT_SPEC(AnimationID.DARK_SPEC_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SARA_SWORD_SPEC(AnimationID.SARADOMIN_SWORD_SPECIAL_PLAYER, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_RED_KERIS_SPEC(AnimationID.TOA_KERIS_PARTISAN_SPECIAL01, AttackStyle.MELEE, MetaData.SPECIAL_ATTACK.d),
|
||||
MELEE_SALAMANDER(AnimationID.HUMAN_ATTACK_SALAMANDER, AttackStyle.MELEE),
|
||||
MELEE_INFERNAL_TECPATL(AnimationID.TECPATL_STAB, AttackStyle.MELEE),
|
||||
MELEE_HALLOWED_FLAIL(AnimationID.HUMAN_WEAPONS_HALLOWED_FLAIL01_ATTACK01, AttackStyle.MELEE),
|
||||
MELEE_FELLING_AXE(AnimationID.FORESTRY_2H_AXE_ATTACK, AttackStyle.MELEE),
|
||||
MELEE_HALLOWFELL(AnimationID.HUMAN_HALLOWFELL_SLASH, AttackStyle.MELEE),
|
||||
|
||||
// RANGED
|
||||
RANGED_CHINCHOMPA(AnimationID.HUMAN_CHINCHOMPA_ATTACK_PVN, AttackStyle.RANGED),
|
||||
RANGED_SHORTBOW(AnimationID.HUMAN_BOW, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d),
|
||||
RANGED_RUNE_KNIFE_PVP(AnimationID.HUMAN_STAKE2, AttackStyle.RANGED),
|
||||
RANGED_MAGIC_SHORTBOW_SPEC(AnimationID.SNAPSHOT, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d | MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_CROSSBOW_PVP(AnimationID.XBOWS_HUMAN_FIRE_AND_RELOAD, AttackStyle.RANGED),
|
||||
RANGED_BLOWPIPE(AnimationID.SNAKEBOSS_BLOWPIPE_ATTACK, AttackStyle.RANGED),
|
||||
RANGED_DARTS(AnimationID.II_HUMAN_DART_THROW_PVN, AttackStyle.RANGED),
|
||||
RANGED_BALLISTA(AnimationID.BALLISTA_ATTACK, AttackStyle.RANGED),
|
||||
RANGED_BALLISTA_SPEC(AnimationID.BALLISTA_SPECIAL_ATTACK_PVN, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_RUNE_THROWNAXE_SPEC(AnimationID.CHAINHIT, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_DRAGON_THROWNAXE_SPEC(AnimationID.HUMAN_DRAGON_TAXE_SPEC, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_RUNE_CROSSBOW(AnimationID.XBOWS_HUMAN_FIRE_AND_RELOAD_PVN, AttackStyle.RANGED),
|
||||
RANGED_RUNE_CROSSBOW_OR(AnimationID.HUMAN_XBOWS_LEAGUE03_ATTACK_PVN, AttackStyle.RANGED),
|
||||
RANGED_BALLISTA_2(AnimationID.BALLISTA_ATTACK_PVN, AttackStyle.RANGED),
|
||||
RANGED_RUNE_KNIFE(AnimationID.HUMAN_STAKE2_PVN, AttackStyle.RANGED),
|
||||
RANGED_DRAGON_KNIFE(AnimationID.HUMAN_DRAGON_KNIFE, AttackStyle.RANGED),
|
||||
RANGED_DRAGON_KNIFE_SPEC(AnimationID.HUMAN_DRAGON_TKNIVES_SPEC, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_DRAGON_KNIFE_POISONED(AnimationID.HUMAN_DRAGON_KNIFE_P, AttackStyle.RANGED),
|
||||
RANGED_DRAGON_KNIFE_POISONED_SPEC(AnimationID.HUMAN_DRAGON_TKNIVES_SPEC_POISON, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_ZARYTE_CROSSBOW(AnimationID.ZCB_ATTACK_PVN, AttackStyle.RANGED),
|
||||
RANGED_ZARYTE_CROSSBOW_PVP(AnimationID.ZCB_ATTACK, AttackStyle.RANGED),
|
||||
RANGED_BLAZING_BLOWPIPE(AnimationID.SNAKEBOSS_BLOWPIPE_ATTACK_ORNAMENT, AttackStyle.RANGED),
|
||||
RANGED_VENATOR_BOW(AnimationID.HUMAN_WEAPON_BOW_VENATOR01_SHOOT, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d),
|
||||
RANGED_KARIL_CROSSBOW(AnimationID.BARROWS_REPEATING_CROSSBOW_FIRE, AttackStyle.RANGED),
|
||||
RANGED_ATLATL(AnimationID.HUMAN_ATLATL_ATTACK_RANGED_01, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d),
|
||||
RANGED_ATLATL_SPEC(AnimationID.HUMAN_SPECIAL_ATLATL_01, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d | MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_TONALZTICS(AnimationID.HUMAN_GLAIVE_RALOS01_CHARGED_THROW, AttackStyle.RANGED),
|
||||
RANGED_TONALZTICS_SPEC(AnimationID.HUMAN_GLAIVE_RALOS01_CHARGED_SPECIAL, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_WEBWEAVER_SPEC(AnimationID.HUMAN_SPECIAL01_WEBWEAVER, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d | MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_BONE_CROSSBOW_SPEC(AnimationID.DTTD_PLAYER_FIRE_BONE_CROSSBOW_PVN, AttackStyle.RANGED, MetaData.SPECIAL_ATTACK.d),
|
||||
RANGED_SCORCHING_BOW_SPEC(AnimationID.HUMAN_WEAPON_BOW_SCORCHED_01_SPEC, AttackStyle.RANGED, MetaData.STANDARD_BOW_ATTACK.d | MetaData.SPECIAL_ATTACK.d),
|
||||
|
||||
// MAGIC
|
||||
MAGIC_GOD_SPELL(AnimationID.HUMAN_CASTING, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_IBAN_BLAST(AnimationID.HUMAN_CASTIBANBLAST, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_SLAYER_DART(AnimationID.SLAYER_MAGICDART_CAST, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_BIND(AnimationID.HUMAN_CASTENTANGLE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_BIND_STAFF(AnimationID.HUMAN_CASTENTANGLE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CONFUSE(AnimationID.HUMAN_CASTCONFUSE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CONFUSE_STAFF(AnimationID.HUMAN_CASTCONFUSE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CONFUSE_STAFF_WALK(AnimationID.HUMAN_CASTCONFUSE_STAFF_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CONFUSE_WALK(AnimationID.HUMAN_CASTCONFUSE_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CRUMBLE_UNDEAD(AnimationID.HUMAN_CASTCRUMBLEUNDEAD, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_CRUMBLE_UNDEAD_HOLDING_STAFF(AnimationID.HUMAN_CASTCRUMBLEUNDEAD_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_ENFEEBLE(AnimationID.HUMAN_CASTENFEEBLE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_STRIKE_BOLT_BLAST(AnimationID.HUMAN_CASTSTRIKE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF(AnimationID.HUMAN_CASTSTRIKE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF_WALK(AnimationID.HUMAN_CASTSTRIKE_STAFF_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_STRIKE_BOLT_BLAST_WALK(AnimationID.HUMAN_CASTSTRIKE_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_STUN(AnimationID.HUMAN_CASTSTUN_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_SURGE(AnimationID.HUMAN_CAST_SURGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_SURGE_STAFF(AnimationID.HUMAN_CAST_SURGE_FAST, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_SURGE_STAFF_WALK(AnimationID.HUMAN_CAST_SURGE_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_VULNERABILITY_CURSE(AnimationID.HUMAN_CASTCURSE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_VULNERABILITY_CURSE_STAFF(AnimationID.HUMAN_CASTCURSE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_VULNERABILITY_CURSE_STAFF_WALK(AnimationID.HUMAN_CASTCURSE_STAFF_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_VULNERABILITY_CURSE_WALK(AnimationID.HUMAN_CASTCURSE_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WAVE(AnimationID.HUMAN_CASTWAVE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WAVE_STAFF(AnimationID.HUMAN_CASTWAVE_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WAVE_STAFF_WALK(AnimationID.HUMAN_CASTWAVE_STAFF_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WAVE_WALK(AnimationID.HUMAN_CASTWAVE_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WEAKEN(AnimationID.HUMAN_CASTWEAKEN, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WEAKEN_STAFF(AnimationID.HUMAN_CASTWEAKEN_STAFF, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WEAKEN_STAFF_WALK(AnimationID.HUMAN_CASTWEAKEN_STAFF_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
MAGIC_STANDARD_WEAKEN_WALK(AnimationID.HUMAN_CASTWEAKEN_WALKMERGE, AttackStyle.MAGIC, Spellbook.STANDARD, MetaData.NO_DATA.d),
|
||||
|
||||
MAGIC_ANCIENT_MULTI_TARGET(AnimationID.ZAROS_VERTICAL_CASTING_WALKMERGE, AttackStyle.MAGIC, Spellbook.ANCIENT, MetaData.NO_DATA.d),
|
||||
MAGIC_ANCIENT_MULTI_TARGET_PVP(AnimationID.ZAROS_VERTICAL_CASTING, AttackStyle.MAGIC, Spellbook.ANCIENT, MetaData.NO_DATA.d),
|
||||
MAGIC_ANCIENT_SINGLE_TARGET(AnimationID.ZAROS_CASTING_WALKMERGE, AttackStyle.MAGIC, Spellbook.ANCIENT, MetaData.NO_DATA.d),
|
||||
MAGIC_ANCIENT_SINGLE_TARGET_PVP(AnimationID.ZAROS_CASTING, AttackStyle.MAGIC, Spellbook.ANCIENT, MetaData.NO_DATA.d),
|
||||
|
||||
MAGIC_ARCEUUS_DEMONBANE(AnimationID.HUMAN_SPELLCAST_DEMONBANE, AttackStyle.MAGIC, Spellbook.ARCEUUS, MetaData.NO_DATA.d),
|
||||
MAGIC_ARCEUUS_GRASP(AnimationID.HUMAN_SPELLCAST_GRASP, AttackStyle.MAGIC, Spellbook.ARCEUUS, MetaData.NO_DATA.d),
|
||||
|
||||
MAGIC_ACCURSED_SCEPTRE_SPEC(AnimationID.HUMAN_SPECIAL_ACCURSED, AttackStyle.MAGIC, MetaData.SPECIAL_ATTACK.d),
|
||||
MAGIC_EYE_OF_AYAK(AnimationID.HUMAN_EYE_OF_AYAK_NORMAL, AttackStyle.MAGIC, MetaData.NO_DATA.d),
|
||||
MAGIC_EYE_OF_AYAK_SPEC(AnimationID.HUMAN_EYE_OF_AYAK_SPECIAL, AttackStyle.MAGIC, MetaData.SPECIAL_ATTACK.d),
|
||||
MAGIC_TUMEKENS_SHADOW(AnimationID.TOA_SOT_CAST_B, AttackStyle.MAGIC, MetaData.NO_DATA.d),
|
||||
MAGIC_VOLATILE_NIGHTMARE_STAFF_SPEC(AnimationID.NIGHTMARE_STAFF_SPECIAL, AttackStyle.MAGIC, MetaData.SPECIAL_ATTACK.d),
|
||||
MAGIC_WARPED_SCEPTRE(AnimationID.POG_WARPED_SCEPTRE_ATTACK, AttackStyle.MAGIC, MetaData.NO_DATA.d),
|
||||
|
||||
// Misc Non-attacks
|
||||
MAGIC_IMBUE(AnimationID.HUMAN_CASTBONESTOBANANAS, AttackStyle.NON_ATTACK),
|
||||
SPELLBOOK_SWAP(AnimationID.DREAM_PLAYER_SPELLBOOK_SWAP, AttackStyle.NON_ATTACK),
|
||||
LUNAR_GROUP(AnimationID.QUEST_LUNAR_SPELL_CAST_SPELL_ON_GROUP, AttackStyle.NON_ATTACK),
|
||||
LUNAR_OTHER(AnimationID.QUEST_LUNAR_PUSHING_MAGIC_ANIMATION, AttackStyle.NON_ATTACK),
|
||||
NPC_CONTACT(AnimationID.LUNAR_HUMAN_MAGIC_SUMMON2, AttackStyle.NON_ATTACK),
|
||||
VENGEANCE_1(AnimationID.VENGEANCE_SPELL_ANIM_NOSTALLING, AttackStyle.NON_ATTACK),
|
||||
VENGEANCE_2(AnimationID.VENGEANCE_SPELL_ANIM_STALLING, AttackStyle.NON_ATTACK),
|
||||
REANIMATION(AnimationID.ARCEUUS_NECROMANCY_PLAYERANIM, AttackStyle.NON_ATTACK),
|
||||
DEMONIC_OFFERING(AnimationID.HUMAN_CAST_OFFERING, AttackStyle.NON_ATTACK),
|
||||
SHADOW_VEIL(AnimationID.HUMAN_SPELLCAST_SHADOWVEIL, AttackStyle.NON_ATTACK),
|
||||
MARK_OF_DARKNESS(AnimationID.HUMAN_CAST_SELFIMBUE, AttackStyle.NON_ATTACK),
|
||||
PICK_POCKETING(AnimationID.HUMAN_PICKPOCKET, AttackStyle.NON_ATTACK),
|
||||
SUMMON_THRALL(AnimationID.HUMAN_SPELLCAST_RESURRECT, AttackStyle.NON_ATTACK),
|
||||
LUNAR_TELEPORT(AnimationID.HUMAN_TELEPORT_OTHER_IMPACT, AttackStyle.NON_ATTACK),
|
||||
MONSTER_EXAMINE(AnimationID.DREAM_PLAYER_MONSTEREXAM_STATSPY, AttackStyle.NON_ATTACK),
|
||||
HUMIDIFY(AnimationID.DREAM_PLAYER_HUMIDIFY_SPELL, AttackStyle.NON_ATTACK),
|
||||
GEOMANCY(AnimationID.LUNAR_HUMAN_MAGIC_GEOMANCY, AttackStyle.NON_ATTACK),
|
||||
DREAM(AnimationID.FOSSIL_LOC_CLAM_IDLE_SHUT, AttackStyle.NON_ATTACK),
|
||||
ROCKSLUG_BAG_OF_SALT(AnimationID.SLAYER_SALT_SPRINKLE, AttackStyle.NON_ATTACK),
|
||||
DESSET_LIZARD_ICE_COOLER(AnimationID.HUMAN_CHINCHOMPA_ATTACK, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_KNIFE(AnimationID.HUMAN_FLETCHING, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_KEBBIT(AnimationID.HUMAN_CRAFTING_SPIKEDVAMBRACES, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_CHISEL(AnimationID.HUMAN_FLETCHING_HUNTINGBOLTS, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_1(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_BRONZE, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_2(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_IRON, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_3(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_STEEL, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_4(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_MITHRIL, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_5(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_ADAMANT, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_6(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_RUNE, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_7(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_DRAGON, AttackStyle.NON_ATTACK),
|
||||
FLECTHING_DART_TIP_8(AnimationID.HUMAN_FLETCHING_ADD_DART_FEATHERS_AMETHYST, AttackStyle.NON_ATTACK),
|
||||
HERB_TAR(AnimationID.HUMAN_SALAMANDER_TAR_GRIND, AttackStyle.NON_ATTACK),
|
||||
SETUP_HUNTER_TRAP(AnimationID.HUMAN_LAYTRAP, AttackStyle.NON_ATTACK),
|
||||
RESET_SNARE_TRAP(AnimationID.HUMAN_HUNTING_DISMANTLE_NET, AttackStyle.NON_ATTACK),
|
||||
RESET_BOX_TRAP(AnimationID.HUNTING_SETTING_TRAP_SMALL, AttackStyle.NON_ATTACK),
|
||||
DESERT_AMMY(AnimationID.TELEPORT_NARDAH_HUMAN, AttackStyle.NON_ATTACK),
|
||||
EAT_FOOD_OR_POTION(AnimationID.HUMAN_EAT, AttackStyle.NON_ATTACK),
|
||||
OVERLOAD_HIT(AnimationID.HUMAN_KILLERWATT_ELECTRICSHOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_1HANDED_UNARMED(AnimationID.HUMAN_AXE_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_2H_SWORD(AnimationID.HUMAN_DHSWORD_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_ANCHOR(AnimationID.BRAIN_PLAYER_ANCHOR_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_BLISTERWOOD_FLAIL(AnimationID.IVANDIS_FLAIL_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_BLOWPIPE(AnimationID.HUMAN_SPEAR_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_BULWARK(AnimationID.HUMAN_DINHS_BULWARK_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_CHAINMACE(AnimationID.WILD_CAVE_CHAINMACE_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_CHIN_CHOMPA(AnimationID.HUMAN_CHINCHOMPA_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_DAGGER(AnimationID.HUMAN_DDAGGER_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_DEFENDER(AnimationID.WARGUILD_PARRY_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_FANG(AnimationID.HUMAN_SWORD_DEF, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_GODSWORD(AnimationID.DH_SWORD_UPDATE_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_KERIS(AnimationID.HUMAN_DSPEAR_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_LARGE_STAFF(AnimationID.HUMAN_STAFFORB_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_MACE(AnimationID.HUMAN_BLUNT_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_OBBY_MAUL(AnimationID.SLAYER_GRANITE_MAUL_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_SCYTHE(AnimationID.HUMAN_SCYTHE_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_SHIELD(AnimationID.HUMAN_SHIELD_DEFENCE, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_SPEAR(AnimationID.HUMAN_ZAMORAKSPEAR_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_STAFF(AnimationID.HUMAN_STAFF_BLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_UNARMED(AnimationID.HUMAN_UNARMEDBLOCK, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_VERACS_FLAIL(AnimationID.BARROW_GUTHAN_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_WHIP(AnimationID.SLAYER_ABYSSAL_WHIP_DEFEND, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_KISTEN(AnimationID.HUMAN_WEAPONS_CRIMSON_KISTEN_DEF, AttackStyle.NON_ATTACK),
|
||||
TAKING_HIT_HALLOWFELL(AnimationID.HUMAN_HALLOWFELL_DEFEND, AttackStyle.NON_ATTACK),
|
||||
LOW_ALCH(AnimationID.HUMAN_CASTLOWLVLALCHEMY, AttackStyle.NON_ATTACK),
|
||||
HIGH_ALCH(AnimationID.HUMAN_CASTHIGHLVLALCHEMY, AttackStyle.NON_ATTACK);
|
||||
|
||||
private static final Map<Integer, AnimationData> DATA;
|
||||
private static final Map<Spellbook, Set<AnimationData>> SPELL_BOOK_ANIMATIONS;
|
||||
private static final Map<Integer, AnimationData> NOT_ATTACKS;
|
||||
private static final Set<Integer> STANDARD_BOW_ATTACKS;
|
||||
|
||||
public final int animationId;
|
||||
public final long metaData;
|
||||
@Getter
|
||||
public final AttackStyle attackStyle;
|
||||
@Getter
|
||||
private final Spellbook spellbook;
|
||||
|
||||
AnimationData(int animationId, AttackStyle attackStyle)
|
||||
{
|
||||
if (attackStyle == null)
|
||||
{
|
||||
throw new InvalidParameterException("Attack Style must be valid for AnimationData");
|
||||
}
|
||||
this.animationId = animationId;
|
||||
this.attackStyle = attackStyle;
|
||||
this.metaData = MetaData.NO_DATA.d;
|
||||
this.spellbook = null;
|
||||
}
|
||||
|
||||
AnimationData(int animationId, AttackStyle attackStyle, long data)
|
||||
{
|
||||
if (attackStyle == null)
|
||||
{
|
||||
throw new InvalidParameterException("Attack Style must be valid for AnimationData");
|
||||
}
|
||||
this.animationId = animationId;
|
||||
this.attackStyle = attackStyle;
|
||||
this.metaData = data;
|
||||
this.spellbook = null;
|
||||
}
|
||||
|
||||
AnimationData(int animationId, AttackStyle attackStyle, Spellbook book, long data)
|
||||
{
|
||||
if (attackStyle == null)
|
||||
{
|
||||
throw new InvalidParameterException("Attack Style must be valid for AnimationData");
|
||||
}
|
||||
this.animationId = animationId;
|
||||
this.attackStyle = attackStyle;
|
||||
this.metaData = data;
|
||||
this.spellbook = book;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, AnimationData> builder = new ImmutableMap.Builder<>();
|
||||
ImmutableMap.Builder<Integer, AnimationData> notAttacksBuilder = new ImmutableMap.Builder<>();
|
||||
Map<Spellbook, Set<AnimationData>> spellBookBuilder = new HashMap<>();
|
||||
ImmutableSet.Builder<Integer> standardBowBuilder = new ImmutableSet.Builder<>();
|
||||
|
||||
for (Spellbook s : Spellbook.values())
|
||||
{
|
||||
spellBookBuilder.put(s, new HashSet<>());
|
||||
}
|
||||
|
||||
for (AnimationData data : values())
|
||||
{
|
||||
builder.put(data.animationId, data);
|
||||
|
||||
if (data.spellbook != null)
|
||||
{
|
||||
if (data.attackStyle != AttackStyle.MAGIC)
|
||||
{
|
||||
throw new InvalidParameterException("Spell book should only be magic animations");
|
||||
}
|
||||
spellBookBuilder.get(data.spellbook).add(data);
|
||||
}
|
||||
if (data.attackStyle == AttackStyle.NON_ATTACK)
|
||||
{
|
||||
notAttacksBuilder.put(data.animationId, data);
|
||||
}
|
||||
|
||||
if (MetaData.hasFlagSet(data.metaData, MetaData.STANDARD_BOW_ATTACK))
|
||||
{
|
||||
standardBowBuilder.add(data.animationId);
|
||||
}
|
||||
}
|
||||
|
||||
DATA = builder.build();
|
||||
NOT_ATTACKS = notAttacksBuilder.build();
|
||||
SPELL_BOOK_ANIMATIONS = spellBookBuilder;
|
||||
STANDARD_BOW_ATTACKS = standardBowBuilder.build();
|
||||
}
|
||||
|
||||
public static AnimationData fromId(int animationId)
|
||||
{
|
||||
return DATA.get(animationId);
|
||||
}
|
||||
|
||||
public static Set<AnimationData> getAnimationsForSpellbook(Spellbook s)
|
||||
{
|
||||
return SPELL_BOOK_ANIMATIONS.get(s);
|
||||
}
|
||||
|
||||
public static boolean isManualCasting(AnimationData animationData)
|
||||
{
|
||||
if (animationData != null && animationData.spellbook != null)
|
||||
{
|
||||
return animationData.attackStyle == AttackStyle.MAGIC &&
|
||||
SPELL_BOOK_ANIMATIONS.get(animationData.spellbook).contains(animationData);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isBlockListAnimation(int animationId)
|
||||
{
|
||||
return NOT_ATTACKS.containsKey(animationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String[] words = super.toString().toLowerCase().split("_");
|
||||
Arrays.stream(words)
|
||||
.map(StringUtils::capitalize).collect(Collectors.toList()).toArray(words);
|
||||
|
||||
return String.join(" ", words);
|
||||
}
|
||||
|
||||
public boolean matchesSpellbook(Spellbook s)
|
||||
{
|
||||
if (this.spellbook != null)
|
||||
{
|
||||
return this.spellbook == s;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStandardBowAttack()
|
||||
{
|
||||
return STANDARD_BOW_ATTACKS.contains(this.animationId);
|
||||
}
|
||||
|
||||
public boolean isBlockListAnimation()
|
||||
{
|
||||
return NOT_ATTACKS.containsKey(this.animationId);
|
||||
}
|
||||
|
||||
public enum AttackStyle
|
||||
{
|
||||
MELEE,
|
||||
RANGED,
|
||||
MAGIC,
|
||||
NON_ATTACK;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return StringUtils.capitalize(super.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
public enum MetaData
|
||||
{
|
||||
NO_DATA(),
|
||||
SPECIAL_ATTACK(1),
|
||||
STANDARD_BOW_ATTACK(2);
|
||||
|
||||
MetaData(int bitshift)
|
||||
{
|
||||
this.d = 1 << bitshift;
|
||||
}
|
||||
MetaData()
|
||||
{
|
||||
this.d = 0;
|
||||
}
|
||||
|
||||
public static boolean hasFlagSet(long input, MetaData data)
|
||||
{
|
||||
return (input & data.d) == data.d;
|
||||
}
|
||||
|
||||
private final long d;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return StringUtils.capitalize(super.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
public enum AttackProcedure
|
||||
{
|
||||
POWERED_STAVE,
|
||||
MANUAL_AUTO_CAST,
|
||||
MELEE_OR_RANGE
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.VariableSpeed;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.FakeXpDrop;
|
||||
import net.runelite.api.events.SoundEffectPlayed;
|
||||
import net.runelite.api.events.StatChanged;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
|
||||
public class AttackSpeed
|
||||
{
|
||||
private final ArrayDeque<Integer> specialPercentageEvents = new ArrayDeque<>();
|
||||
private final Damage damage = new Damage();
|
||||
@Getter
|
||||
private int dmgDealt = -1;
|
||||
private final TickCount tickCount;
|
||||
private final VariableSpeed variableSpeed;
|
||||
@Getter
|
||||
private int soundEffectTick = -1;
|
||||
@Getter
|
||||
private int soundEffectId = -1;
|
||||
@Getter
|
||||
private boolean isUsingMagic = false;
|
||||
|
||||
public AttackSpeed(final TickCount tc, final VariableSpeed vs)
|
||||
{
|
||||
this.tickCount = tc;
|
||||
this.variableSpeed = vs;
|
||||
}
|
||||
|
||||
public int compute(final Client client, final AnimationData curAnimation, final Spellbook spellbook, final ItemManager itemManager)
|
||||
{
|
||||
final int weaponId = CombatUtils.getWeaponId(client);
|
||||
final PoweredStaves stave = PoweredStaves.getPoweredStaves(weaponId, curAnimation);
|
||||
final int specDelta = CombatUtils.getLastDelta(specialPercentageEvents);
|
||||
dmgDealt = damage.compute(tickCount);
|
||||
if (stave != null && stave.getAnimations() != null && stave.getAnimations().contains(curAnimation))
|
||||
{
|
||||
isUsingMagic = true;
|
||||
return variableSpeed.compute(client, curAnimation, AttackProcedure.POWERED_STAVE, spellbook, dmgDealt, specDelta, 4);
|
||||
}
|
||||
|
||||
if (matchesSpellbook(client, curAnimation, spellbook) && ManualCasting.is(client, curAnimation, soundEffectTick, soundEffectId))
|
||||
{
|
||||
isUsingMagic = true;
|
||||
return variableSpeed.compute(client, curAnimation, AttackProcedure.MANUAL_AUTO_CAST, spellbook, dmgDealt, specDelta, getMagicBaseSpeed(weaponId));
|
||||
}
|
||||
|
||||
isUsingMagic = false;
|
||||
final int aspeed = CombatUtils.getWeaponSpeed(client, itemManager, weaponId);
|
||||
return variableSpeed.compute(client, curAnimation, AttackProcedure.MELEE_OR_RANGE, spellbook, dmgDealt, specDelta, aspeed);
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
while (specialPercentageEvents.size() > 5)
|
||||
{
|
||||
specialPercentageEvents.removeFirst();
|
||||
}
|
||||
damage.onTick();
|
||||
}
|
||||
|
||||
public void varbitSpecialAttackChanged(final int value)
|
||||
{
|
||||
specialPercentageEvents.addLast(value);
|
||||
}
|
||||
|
||||
public boolean onXpDrop(final FakeXpDrop event)
|
||||
{
|
||||
return damage.onXpDrop(event, tickCount);
|
||||
}
|
||||
|
||||
public boolean onXpDrop(final StatChanged event)
|
||||
{
|
||||
return damage.onXpDrop(event, tickCount);
|
||||
}
|
||||
|
||||
public void onSoundEffectPlayed(final Client client, final SoundEffectPlayed event)
|
||||
{
|
||||
soundEffectTick = client.getTickCount();
|
||||
soundEffectId = event.getSoundId();
|
||||
}
|
||||
|
||||
private static final Map<Integer, Integer> NON_STANDARD_MAGIC_WEAPON_SPEEDS = new ImmutableMap.Builder<Integer, Integer>()
|
||||
.put(ItemID.TWINFLAME_STAFF, 6)
|
||||
.build();
|
||||
|
||||
private static int getMagicBaseSpeed(final int weaponId)
|
||||
{
|
||||
if (weaponId == ItemID.NIGHTMARE_STAFF_HARMONISED)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return NON_STANDARD_MAGIC_WEAPON_SPEEDS.getOrDefault(weaponId, 5);
|
||||
}
|
||||
|
||||
private boolean matchesSpellbook(final Client client, final AnimationData curAnimation, final Spellbook currentSpellBook)
|
||||
{
|
||||
if (curAnimation != null && curAnimation.getAttackStyle() == AnimationData.AttackStyle.MAGIC && curAnimation.getSpellbook() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (curAnimation != null && curAnimation.matchesSpellbook(currentSpellBook))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (client.getTickCount() == soundEffectTick)
|
||||
{
|
||||
return CastingSoundData.getSpellBookFromId(soundEffectId) == currentSpellBook;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
dmgDealt = -1;
|
||||
soundEffectId = -1;
|
||||
soundEffectTick = -1;
|
||||
isUsingMagic = false;
|
||||
specialPercentageEvents.clear();
|
||||
damage.reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Skill;
|
||||
|
||||
public enum AttackStyle
|
||||
{
|
||||
ACCURATE("Accurate", Skill.ATTACK),
|
||||
AGGRESSIVE("Aggressive", Skill.STRENGTH),
|
||||
DEFENSIVE("Defensive", Skill.DEFENCE),
|
||||
CONTROLLED("Controlled", Skill.ATTACK, Skill.STRENGTH, Skill.DEFENCE),
|
||||
RANGING("Ranging", Skill.RANGED),
|
||||
LONGRANGE("Longrange", Skill.RANGED, Skill.DEFENCE),
|
||||
CASTING("Casting", Skill.MAGIC),
|
||||
DEFENSIVE_CASTING("Defensive Casting", Skill.MAGIC, Skill.DEFENCE),
|
||||
OTHER("Other");
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
@Getter
|
||||
private final Skill[] skills;
|
||||
|
||||
AttackStyle(String name, Skill... skills)
|
||||
{
|
||||
this.name = name;
|
||||
this.skills = skills;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
public enum AttackType
|
||||
{
|
||||
CRUSH,
|
||||
SLASH,
|
||||
STAB,
|
||||
RANGED,
|
||||
MAGIC,
|
||||
NONE;
|
||||
|
||||
public boolean IsMelee()
|
||||
{
|
||||
return this.equals(CRUSH) || this.equals(SLASH) || this.equals(STAB);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Actor;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
import net.runelite.api.gameval.SpotanimID;
|
||||
import net.runelite.client.game.NPCManager;
|
||||
|
||||
public class Attacking
|
||||
{
|
||||
private static final Set<AnimationData> UNRELIABLE_ANIMATIONS = new ImmutableSet.Builder<AnimationData>()
|
||||
.add(AnimationData.RANGED_BLOWPIPE).add(AnimationData.RANGED_BLAZING_BLOWPIPE)
|
||||
.add(AnimationData.MAGIC_EYE_OF_AYAK).add(AnimationData.MAGIC_EYE_OF_AYAK_SPEC).build();
|
||||
|
||||
private static final Set<Integer> SPECIAL_NPCS = new ImmutableSet.Builder<Integer>()
|
||||
.add(NpcID.POH_COMBAT_DUMMY_UPGRADED_UNDEADSLAYER_NPC, NpcID.POH_COMBAT_DUMMY_UPGRADED_ETHER_NPC,
|
||||
NpcID.POH_COMBAT_DUMMY_UPGRADED_KQ_NPC, NpcID.POH_COMBAT_DUMMY_UPGRADED_KURASK_NPC,
|
||||
NpcID.POH_COMBAT_DUMMY_UPGRADED_VAMPIRE_NPC, NpcID.POH_COMBAT_DUMMY_UPGRADED_VORKATH_NPC,
|
||||
NpcID.POH_COMBAT_DUMMY_NPC, NpcID.POH_COMBAT_DUMMY_UNDEADSLAYER_NPC,
|
||||
NpcID.POH_COMBAT_DUMMY_UPGRADED_NPC, NpcID.NIGHTMARE_TOTEM_1_READY, NpcID.NIGHTMARE_TOTEM_2_READY,
|
||||
NpcID.NIGHTMARE_TOTEM_3_READY, NpcID.NIGHTMARE_TOTEM_4_READY)
|
||||
.build();
|
||||
|
||||
public static boolean isPlayerAttacking(final Client client, final NPCManager npcManager)
|
||||
{
|
||||
final Player localPlayer = client.getLocalPlayer();
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final int animationId = localPlayer.getAnimation();
|
||||
if (AnimationData.isBlockListAnimation(animationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean notWalking = animationId != -1 || getSalamanderAttack(client);
|
||||
|
||||
final Actor target = localPlayer.getInteracting();
|
||||
if (target instanceof NPC)
|
||||
{
|
||||
final NPC npc = (NPC) target;
|
||||
final boolean containsAttackOption = npc.getComposition() != null
|
||||
&& npc.getComposition().getActions() != null
|
||||
&& Arrays.asList(npc.getComposition().getActions()).contains("Attack");
|
||||
Integer health = null;
|
||||
if (npcManager != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
health = npcManager.getHealth(npc.getId());
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
final boolean hasHealthAndLevel = health != null && health > 0 && target.getCombatLevel() > 0;
|
||||
final boolean attackingNPC = hasHealthAndLevel || SPECIAL_NPCS.contains(npc.getId()) || containsAttackOption;
|
||||
return attackingNPC && notWalking;
|
||||
}
|
||||
if (target instanceof Player)
|
||||
{
|
||||
return notWalking;
|
||||
}
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final AnimationData fromId = AnimationData.fromId(animationId);
|
||||
if (UNRELIABLE_ANIMATIONS.contains(fromId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return fromId != null;
|
||||
}
|
||||
|
||||
public static Attack playerAttack(final Client client)
|
||||
{
|
||||
final Player localPlayer = client.getLocalPlayer();
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return new Attack(-1, false, null);
|
||||
}
|
||||
final int animationId = localPlayer.getAnimation();
|
||||
final Actor target = localPlayer.getInteracting();
|
||||
return new Attack(animationId, getSalamanderAttack(client), target);
|
||||
}
|
||||
|
||||
private static boolean getSalamanderAttack(final Client client)
|
||||
{
|
||||
Player localPlayer = client.getLocalPlayer();
|
||||
return localPlayer != null && localPlayer.hasSpotAnim(SpotanimID.FIREBREATH);
|
||||
}
|
||||
|
||||
public static final class Attack
|
||||
{
|
||||
@Getter
|
||||
private final int animationId;
|
||||
@Getter
|
||||
private final boolean salamander;
|
||||
@Getter
|
||||
private final Actor target;
|
||||
|
||||
public Attack(final int animationId, final boolean salamander, final Actor target)
|
||||
{
|
||||
this.animationId = animationId;
|
||||
this.salamander = salamander;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public enum CastingSoundData
|
||||
{
|
||||
STANDARD_BIND(101, Spellbook.STANDARD),
|
||||
STANDARD_CONFUSE(119, Spellbook.STANDARD),
|
||||
STANDARD_CRUMBLE_UNDEAD(122, Spellbook.STANDARD),
|
||||
STANDARD_CURSE(127, Spellbook.STANDARD),
|
||||
STANDARD_EARTH_BLAST(128, Spellbook.STANDARD),
|
||||
STANDARD_EARTH_BOLT(130, Spellbook.STANDARD),
|
||||
STANDARD_EARTH_STRIKE(132, Spellbook.STANDARD),
|
||||
STANDARD_EARTH_SURGE(4025, Spellbook.STANDARD),
|
||||
STANDARD_EARTH_WAVE(134, Spellbook.STANDARD),
|
||||
STANDARD_ENFEEBLE(148, Spellbook.STANDARD),
|
||||
STANDARD_ENTANGLE(151, Spellbook.STANDARD),
|
||||
STANDARD_FIRE_BLAST(155, Spellbook.STANDARD),
|
||||
STANDARD_FIRE_BOLT(157, Spellbook.STANDARD),
|
||||
STANDARD_FIRE_STRIKE(160, Spellbook.STANDARD),
|
||||
STANDARD_FIRE_SURGE(4032, Spellbook.STANDARD),
|
||||
STANDARD_IBANS_BLAST_FIRE_WAVE(162, Spellbook.STANDARD),
|
||||
STANDARD_SLAYER_DART(1718, Spellbook.STANDARD),
|
||||
STANDARD_SNARE(3003, Spellbook.STANDARD),
|
||||
STANDARD_STUN(3004, Spellbook.STANDARD),
|
||||
STANDARD_VULNERABILITY(3009, Spellbook.STANDARD),
|
||||
STANDARD_WATER_BLAST(207, Spellbook.STANDARD),
|
||||
STANDARD_WATER_BOLT(209, Spellbook.STANDARD),
|
||||
STANDARD_WATER_STRIKE(221, Spellbook.STANDARD),
|
||||
STANDARD_WATER_SURGE(4030, Spellbook.STANDARD),
|
||||
STANDARD_WATER_WAVE(213, Spellbook.STANDARD),
|
||||
STANDARD_WEAKEN(3011, Spellbook.STANDARD),
|
||||
STANDARD_WIND_BLAST(216, Spellbook.STANDARD),
|
||||
STANDARD_WIND_BOLT(218, Spellbook.STANDARD),
|
||||
STANDARD_WIND_STRIKE(220, Spellbook.STANDARD),
|
||||
STANDARD_WIND_SURGE(4028, Spellbook.STANDARD),
|
||||
STANDARD_WIND_WAVE(222, Spellbook.STANDARD),
|
||||
|
||||
ANCIENT_BLOOD_SPELL(106, Spellbook.ANCIENT),
|
||||
ANCIENT_ICE_SPELL(171, Spellbook.ANCIENT),
|
||||
ANCIENT_SHADOW_SPELL(178, Spellbook.ANCIENT),
|
||||
ANCIENT_SMOKE_SPELL(183, Spellbook.ANCIENT),
|
||||
|
||||
ARCEUUS_DARK_DEMONBANE(5053, Spellbook.ARCEUUS),
|
||||
ARCEUUS_GHOSTLY_GRASP(5042, Spellbook.ARCEUUS),
|
||||
ARCEUUS_INFERIOR_DEMONBANE(5038, Spellbook.ARCEUUS),
|
||||
ARCEUUS_SKELETAL_GRASP(5026, Spellbook.ARCEUUS),
|
||||
ARCEUUS_SUPERIOR_DEMONBANE(5027, Spellbook.ARCEUUS),
|
||||
ARCEUUS_UNDEAD_GRASP(5030, Spellbook.ARCEUUS);
|
||||
|
||||
private final int id;
|
||||
private final Spellbook spellbook;
|
||||
|
||||
CastingSoundData(int id, Spellbook b)
|
||||
{
|
||||
this.id = id;
|
||||
this.spellbook = b;
|
||||
}
|
||||
|
||||
private static final ImmutableMap<Integer, CastingSoundData> SOUNDS;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, CastingSoundData> builder = new ImmutableMap.Builder<>();
|
||||
for (CastingSoundData data : values())
|
||||
{
|
||||
builder.put(data.id, data);
|
||||
}
|
||||
SOUNDS = builder.build();
|
||||
}
|
||||
|
||||
public static boolean isCastingSound(int id)
|
||||
{
|
||||
return SOUNDS.containsKey(id);
|
||||
}
|
||||
|
||||
public static Spellbook getSpellBookFromId(int id)
|
||||
{
|
||||
if (!SOUNDS.containsKey(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return SOUNDS.get(id).spellbook;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.runelite.api.Actor;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.EquipmentInventorySlot;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.WorldView;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.gameval.InventoryID;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.api.gameval.VarPlayerID;
|
||||
import net.runelite.api.gameval.VarbitID;
|
||||
import net.runelite.client.game.ItemEquipmentStats;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemStats;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
public class CombatUtils
|
||||
{
|
||||
public static int getItemIdFromContainer(final ItemContainer container, final int slotID)
|
||||
{
|
||||
if (container == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
final Item item = container.getItem(slotID);
|
||||
return (item != null) ? item.getId() : -1;
|
||||
}
|
||||
|
||||
public static int getWeaponIdRaw(final Client client)
|
||||
{
|
||||
return getItemIdFromContainer(client.getItemContainer(InventoryID.WORN),
|
||||
EquipmentInventorySlot.WEAPON.getSlotIdx());
|
||||
}
|
||||
|
||||
public static WorldPoint getLocalLocation(final Client client)
|
||||
{
|
||||
final LocalPoint localPoint = client.getLocalPlayer().getLocalLocation();
|
||||
return WorldPoint.fromLocalInstance(client, localPoint);
|
||||
}
|
||||
|
||||
public static AttackStyle getAttackStyle(final Client client)
|
||||
{
|
||||
final AttackStyle[] attackStyles = getWeaponType(client).getAttackStyles(client);
|
||||
int currentAttackStyleVarbit = client.getVarpValue(VarPlayerID.COM_MODE);
|
||||
final int castingMode = client.getVarbitValue(VarbitID.AUTOCAST_DEFMODE);
|
||||
if (currentAttackStyleVarbit < attackStyles.length)
|
||||
{
|
||||
if (currentAttackStyleVarbit == 4)
|
||||
{
|
||||
currentAttackStyleVarbit += castingMode;
|
||||
}
|
||||
return attackStyles[currentAttackStyleVarbit];
|
||||
}
|
||||
return AttackStyle.ACCURATE;
|
||||
}
|
||||
|
||||
public static WeaponType getWeaponType(final Client client)
|
||||
{
|
||||
final int currentEquippedWeaponTypeVarbit = client.getVarbitValue(VarbitID.COMBAT_WEAPON_CATEGORY);
|
||||
return WeaponType.getWeaponType(currentEquippedWeaponTypeVarbit);
|
||||
}
|
||||
|
||||
public static AttackType getAttackType(final Client client)
|
||||
{
|
||||
final WeaponType weaponType = getWeaponType(client);
|
||||
final int currentAttackStyleVarbit = client.getVarpValue(VarPlayerID.COM_MODE);
|
||||
if (currentAttackStyleVarbit < weaponType.getAttackTypes().length)
|
||||
{
|
||||
return weaponType.getAttackTypes()[currentAttackStyleVarbit];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getTargetId(final Client client)
|
||||
{
|
||||
final NPC target = getTargetNPC(client);
|
||||
int targetId = 0;
|
||||
if (target != null)
|
||||
{
|
||||
targetId = target.getId();
|
||||
}
|
||||
return targetId;
|
||||
}
|
||||
|
||||
public static NPC getTargetNPC(final Client client)
|
||||
{
|
||||
final Actor target = client.getLocalPlayer().getInteracting();
|
||||
if (target != null && (target instanceof NPC))
|
||||
{
|
||||
return (NPC) target;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isInRegionId(final Client client, final int id)
|
||||
{
|
||||
final int[] regions = regions(client);
|
||||
if (regions == null || regions.length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ArrayUtils.contains(regions, id);
|
||||
}
|
||||
|
||||
public static boolean isInRegionId(final Client client, final Set<Integer> ids)
|
||||
{
|
||||
final int[] regions = regions(client);
|
||||
if (regions == null || regions.length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (final int id : regions)
|
||||
{
|
||||
if (ids.contains(id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int[] regions(final Client client)
|
||||
{
|
||||
final WorldView wv = client.getTopLevelWorldView();
|
||||
if (wv == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return wv.getMapRegions();
|
||||
}
|
||||
|
||||
public static int getLastDelta(final ArrayDeque<Integer> events)
|
||||
{
|
||||
int i = 0, last = -1, secondLast = -1;
|
||||
final var it = events.descendingIterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
last = it.next();
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
secondLast = it.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return last - secondLast;
|
||||
}
|
||||
|
||||
private static final Map<Integer, Integer> WEAPON_ID_MAPPING_WORKAROUNDS = new ImmutableMap.Builder<Integer, Integer>()
|
||||
.put(ItemID.VENATOR_BOW_ORNAMENT, ItemID.VENATOR_BOW)
|
||||
.build();
|
||||
|
||||
private static final Map<Integer, Integer> NON_STANDARD_ATTACK_SPEEDS = new ImmutableMap.Builder<Integer, Integer>()
|
||||
.put(ItemID.HALLOWFELL, 6)
|
||||
.build();
|
||||
|
||||
public static int getWeaponId(final Client client)
|
||||
{
|
||||
final int weaponId = getWeaponIdRaw(client);
|
||||
return WEAPON_ID_MAPPING_WORKAROUNDS.getOrDefault(weaponId, weaponId);
|
||||
}
|
||||
|
||||
public static ItemStats getWeaponStats(final Client client, final ItemManager itemManager, final int weaponId)
|
||||
{
|
||||
if (NON_STANDARD_ATTACK_SPEEDS.containsKey(weaponId))
|
||||
{
|
||||
return new ItemStats(true, -1, -1,
|
||||
ItemEquipmentStats.builder().aspeed(NON_STANDARD_ATTACK_SPEEDS.get(weaponId)).build());
|
||||
}
|
||||
return itemManager.getItemStats(weaponId);
|
||||
}
|
||||
|
||||
public static int getWeaponSpeed(final Client client, final ItemManager itemManager, final int weaponId)
|
||||
{
|
||||
final ItemStats weaponStats = getWeaponStats(client, itemManager, weaponId);
|
||||
if (weaponStats == null || weaponStats.getEquipment() == null)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return weaponStats.getEquipment().getAspeed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import java.util.ArrayDeque;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.events.FakeXpDrop;
|
||||
import net.runelite.api.events.StatChanged;
|
||||
|
||||
public class Damage
|
||||
{
|
||||
private static final double MODIFIER = 1;
|
||||
private static final double GLOBAL_MODIFIER = 1;
|
||||
|
||||
private final ArrayDeque<Integer> hpExpEarned = new ArrayDeque<>();
|
||||
private final ArrayDeque<Integer> hpExpEarnedTickCount = new ArrayDeque<>();
|
||||
|
||||
public boolean onXpDrop(StatChanged event, TickCount tc)
|
||||
{
|
||||
if (event.getSkill() != Skill.HITPOINTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
hpExpEarnedTickCount.addLast(tc.get());
|
||||
hpExpEarned.addLast(event.getXp());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onXpDrop(FakeXpDrop event, TickCount tc)
|
||||
{
|
||||
if (event.getSkill() != Skill.HITPOINTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
hpExpEarnedTickCount.addLast(tc.get());
|
||||
hpExpEarnedTickCount.addLast(tc.get());
|
||||
hpExpEarned.addLast(0);
|
||||
hpExpEarned.addLast(event.getXp());
|
||||
return true;
|
||||
}
|
||||
|
||||
public int compute(TickCount tc)
|
||||
{
|
||||
if (hpExpEarnedTickCount.isEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
final int lastTc = hpExpEarnedTickCount.getLast();
|
||||
if (!tc.isWithinNTicks(lastTc, 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
final double xp = (double) CombatUtils.getLastDelta(hpExpEarned);
|
||||
return (int) Math.round(xp * (3.0d / 4.0d) * MODIFIER * GLOBAL_MODIFIER);
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
while (hpExpEarnedTickCount.size() > 5)
|
||||
{
|
||||
hpExpEarnedTickCount.removeFirst();
|
||||
}
|
||||
while (hpExpEarned.size() > 5)
|
||||
{
|
||||
hpExpEarned.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
hpExpEarned.clear();
|
||||
hpExpEarnedTickCount.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import net.runelite.api.Client;
|
||||
|
||||
public class ManualCasting
|
||||
{
|
||||
public static boolean is(final Client client, final AnimationData curId, final int soundEffectTick, final int soundEffectId)
|
||||
{
|
||||
final boolean castingFromSound = client.getTickCount() == soundEffectTick
|
||||
? CastingSoundData.isCastingSound(soundEffectId)
|
||||
: false;
|
||||
final boolean castingFromAnimation = AnimationData.isManualCasting(curId);
|
||||
return castingFromSound || castingFromAnimation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public enum PoweredStaves
|
||||
{
|
||||
WEAPON_ACCURSED(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK,
|
||||
AnimationData.MAGIC_ACCURSED_SCEPTRE_SPEC), ItemID.WILD_CAVE_ACCURSED_CHARGED),
|
||||
WEAPON_GAUNTLET_STAFF(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.GAUNTLET_MAGIC_T1, ItemID.GAUNTLET_MAGIC_T2, ItemID.GAUNTLET_MAGIC_T3, ItemID.GAUNTLET_MAGIC_T1_HM,
|
||||
ItemID.GAUNTLET_MAGIC_T2_HM, ItemID.GAUNTLET_MAGIC_T3_HM),
|
||||
WEAPON_BONE_STAFF(AnimationData.MELEE_GENERIC_SLASH, ItemID.RAT_BONE_STAFF),
|
||||
WEAPON_DAWNBRINGER(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.VERZIK_SPECIAL_WEAPON),
|
||||
WEAPON_HARM(Set.of(AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF,
|
||||
AnimationData.MAGIC_STANDARD_SURGE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK,
|
||||
AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF_WALK, AnimationData.MAGIC_STANDARD_SURGE_STAFF_WALK),
|
||||
ItemID.NIGHTMARE_STAFF_HARMONISED),
|
||||
WEAPON_SANG(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.SANGUINESTI_STAFF, ItemID.SANGUINESTI_STAFF_OR),
|
||||
WEAPON_STARTER_STAFF(ItemID.DEADMAN_STARTER_STAFF, ItemID.DEADMAN_APOCALYPSE_STAFF),
|
||||
WEAPON_SWAMP(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.TOXIC_TOTS_CHARGED, ItemID.TOXIC_TOTS_I_CHARGED, ItemID.TOXIC_TOTS_CHARGED_ORN,
|
||||
ItemID.TOXIC_TOTS_I_CHARGED_ORN),
|
||||
WEAPON_THAMMARON(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.WILD_CAVE_SCEPTRE_CHARGED),
|
||||
WEAPON_TRIDENT(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK),
|
||||
ItemID.TOTS, ItemID.TOTS_CHARGED, ItemID.TOTS_I_CHARGED, ItemID.TOTS_CHARGED_ORN, ItemID.TOTS_ORN,
|
||||
ItemID.TOTS_I_CHARGED_ORN),
|
||||
WEAPON_WARPED_SCEPTRE(AnimationData.MAGIC_WARPED_SCEPTRE, ItemID.WARPED_SCEPTRE);
|
||||
|
||||
@Getter
|
||||
private final Set<Integer> ids;
|
||||
@Getter
|
||||
private final Set<AnimationData> animations;
|
||||
|
||||
private static Set<Integer> ListToSet(int... id)
|
||||
{
|
||||
ImmutableSet.Builder<Integer> builder = new ImmutableSet.Builder<>();
|
||||
if (id.length == 0)
|
||||
{
|
||||
return builder.build();
|
||||
}
|
||||
for (int i : id)
|
||||
{
|
||||
builder.add(i);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
PoweredStaves(int... id)
|
||||
{
|
||||
this.ids = ListToSet(id);
|
||||
this.animations = null;
|
||||
}
|
||||
|
||||
PoweredStaves(AnimationData spell, int... id)
|
||||
{
|
||||
this.ids = ListToSet(id);
|
||||
this.animations = Set.of(spell);
|
||||
}
|
||||
|
||||
PoweredStaves(Set<AnimationData> spell, int... id)
|
||||
{
|
||||
this.ids = ListToSet(id);
|
||||
this.animations = spell;
|
||||
}
|
||||
|
||||
protected static final int UNKNOWN_SPELL = 0xDEADBEEF;
|
||||
protected static final ImmutableMap<Integer, ImmutableMap<Integer, PoweredStaves>> POWERED_STAVES;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, ImmutableMap<Integer, PoweredStaves>> builder = new ImmutableMap.Builder<>();
|
||||
|
||||
for (PoweredStaves p : values())
|
||||
{
|
||||
for (int id : p.ids)
|
||||
{
|
||||
ImmutableMap.Builder<Integer, PoweredStaves> spellMap = new ImmutableMap.Builder<>();
|
||||
if (p.animations == null)
|
||||
{
|
||||
spellMap.put(UNKNOWN_SPELL, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (AnimationData spell : p.animations)
|
||||
{
|
||||
spellMap.put(spell.animationId, p);
|
||||
}
|
||||
}
|
||||
builder.put(id, spellMap.build());
|
||||
}
|
||||
}
|
||||
|
||||
POWERED_STAVES = builder.build();
|
||||
}
|
||||
|
||||
public static PoweredStaves getPoweredStaves(int weaponId, AnimationData animation)
|
||||
{
|
||||
ImmutableMap<Integer, PoweredStaves> weaponMap = POWERED_STAVES.get(weaponId);
|
||||
if (weaponMap == null || animation == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (weaponMap.containsKey(UNKNOWN_SPELL))
|
||||
{
|
||||
return weaponMap.get(UNKNOWN_SPELL);
|
||||
}
|
||||
return weaponMap.get(animation.animationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String[] words = super.toString().toLowerCase().split("_");
|
||||
Arrays.stream(words).map(StringUtils::capitalize).collect(Collectors.toList()).toArray(words);
|
||||
return String.join(" ", words);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public enum Spellbook
|
||||
{
|
||||
STANDARD(0),
|
||||
ANCIENT(1),
|
||||
LUNAR(2),
|
||||
ARCEUUS(3);
|
||||
|
||||
private final int id;
|
||||
|
||||
Spellbook(int id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private static final ImmutableMap<Integer, Spellbook> BOOKS;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, Spellbook> builder = new ImmutableMap.Builder<>();
|
||||
for (Spellbook data : values())
|
||||
{
|
||||
builder.put(data.id, data);
|
||||
}
|
||||
BOOKS = builder.build();
|
||||
}
|
||||
|
||||
public static Spellbook fromVarbit(int varbit)
|
||||
{
|
||||
return BOOKS.get(varbit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.example.essentialsplus.helpers.combat;
|
||||
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.ACCURATE;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.AGGRESSIVE;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.CASTING;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.DEFENSIVE;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.DEFENSIVE_CASTING;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackStyle.OTHER;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.CRUSH;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.MAGIC;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.NONE;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.RANGED;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.SLASH;
|
||||
import static com.example.essentialsplus.helpers.combat.AttackType.STAB;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.EnumID;
|
||||
import net.runelite.api.ParamID;
|
||||
import net.runelite.api.StructComposition;
|
||||
|
||||
public enum WeaponType
|
||||
{
|
||||
UNARMED(CRUSH, CRUSH, null, CRUSH),
|
||||
AXE(SLASH, SLASH, CRUSH, SLASH),
|
||||
BLUNT(CRUSH, CRUSH, null, CRUSH),
|
||||
BOW(RANGED, RANGED, null, RANGED),
|
||||
CLAW(SLASH, SLASH, STAB, SLASH),
|
||||
HEAVY_RANGED(RANGED, RANGED, null, RANGED),
|
||||
SALAMANDER(SLASH, RANGED, MAGIC, null),
|
||||
CHINCHOMPA(RANGED, RANGED, null, RANGED),
|
||||
GUN(NONE, CRUSH, null, null),
|
||||
SLASH_SWORD(SLASH, SLASH, STAB, SLASH),
|
||||
TWO_HANDED_SWORD(SLASH, SLASH, CRUSH, SLASH),
|
||||
PICKAXE(STAB, STAB, CRUSH, STAB),
|
||||
POLEARM(STAB, SLASH, null, STAB),
|
||||
POLESTAFF(CRUSH, CRUSH, null, CRUSH),
|
||||
SCYTHE(SLASH, SLASH, CRUSH, SLASH),
|
||||
SPEAR(STAB, SLASH, CRUSH, STAB),
|
||||
SPIKED(CRUSH, CRUSH, STAB, CRUSH),
|
||||
STAB_SWORD(STAB, STAB, SLASH, STAB),
|
||||
STAFF(CRUSH, CRUSH, null, CRUSH, MAGIC, MAGIC),
|
||||
THROWN(RANGED, RANGED, null, RANGED),
|
||||
WHIP(SLASH, SLASH, null, SLASH),
|
||||
BLADED_STAFF(STAB, SLASH, null, CRUSH, MAGIC, MAGIC),
|
||||
TWO_HANDED_SWORD_GODSWORD(STAB, SLASH, null, CRUSH, MAGIC, MAGIC),
|
||||
POWERED_STAFF(SLASH, SLASH, CRUSH, SLASH),
|
||||
BANNER(MAGIC, MAGIC, null, MAGIC),
|
||||
POLEARM_CRYSTAL_HALBERD(STAB, SLASH, CRUSH, STAB),
|
||||
BLUDGEON(STAB, SLASH, null, STAB),
|
||||
BULWARK(CRUSH, CRUSH, null, CRUSH),
|
||||
POWERED_WAND(CRUSH, null, null, NONE),
|
||||
PARTISAN(MAGIC, MAGIC, null, MAGIC),
|
||||
PARTISAN_2(STAB, STAB, CRUSH, STAB),
|
||||
PLACE_HOLDER_0(null, null, null),
|
||||
PLACE_HOLDER_1(null, null, null),
|
||||
PLACE_HOLDER_2(null, null, null),
|
||||
PLACE_HOLDER_3(null, null, null),
|
||||
FLAIL(SLASH, SLASH, null, SLASH);
|
||||
|
||||
private static final Map<Integer, WeaponType> WEAPON_TYPES;
|
||||
|
||||
@Getter
|
||||
private final AttackType[] attackTypes;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, WeaponType> builder = new ImmutableMap.Builder<>();
|
||||
for (WeaponType weaponType : values())
|
||||
{
|
||||
builder.put(weaponType.ordinal(), weaponType);
|
||||
}
|
||||
WEAPON_TYPES = builder.build();
|
||||
}
|
||||
|
||||
WeaponType(AttackType... attackTypes)
|
||||
{
|
||||
this.attackTypes = attackTypes;
|
||||
}
|
||||
|
||||
public AttackStyle[] getAttackStyles(Client client)
|
||||
{
|
||||
int weaponType = this.ordinal();
|
||||
int weaponStyleEnum = client.getEnum(EnumID.WEAPON_STYLES).getIntValue(weaponType);
|
||||
if (weaponStyleEnum == -1)
|
||||
{
|
||||
if (weaponType == 22)
|
||||
{
|
||||
return new AttackStyle[]{
|
||||
ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING,
|
||||
};
|
||||
}
|
||||
|
||||
if (weaponType == 30)
|
||||
{
|
||||
return new AttackStyle[]{
|
||||
ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE,
|
||||
};
|
||||
}
|
||||
return new AttackStyle[0];
|
||||
}
|
||||
int[] weaponStyleStructs = client.getEnum(weaponStyleEnum).getIntVals();
|
||||
|
||||
AttackStyle[] styles = new AttackStyle[weaponStyleStructs.length];
|
||||
int i = 0;
|
||||
for (int style : weaponStyleStructs)
|
||||
{
|
||||
StructComposition attackStyleStruct = client.getStructComposition(style);
|
||||
String attackStyleName = attackStyleStruct.getStringValue(ParamID.ATTACK_STYLE_NAME);
|
||||
AttackStyle attackStyle = AttackStyle.valueOf(attackStyleName.toUpperCase());
|
||||
if (attackStyle == OTHER)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 5 && attackStyle == DEFENSIVE)
|
||||
{
|
||||
attackStyle = DEFENSIVE_CASTING;
|
||||
}
|
||||
|
||||
styles[i++] = attackStyle;
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
|
||||
public static WeaponType getWeaponType(int id)
|
||||
{
|
||||
return WEAPON_TYPES.get(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.AttackType;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
|
||||
public class Amoxliatl implements IVariableSpeed
|
||||
{
|
||||
private static final int AMOXLIATL_REGION_ID = 5446;
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final WorldPoint location = CombatUtils.getLocalLocation(client);
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
final AttackType attkType = CombatUtils.getAttackType(client);
|
||||
if (location.getRegionID() == AMOXLIATL_REGION_ID && targetId == NpcID.AMOXLIATL_ICE_BLOCK && attkType != null && attkType.IsMelee())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.gameval.SpotanimID;
|
||||
|
||||
public class BloodMoonSet implements IVariableSpeed
|
||||
{
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
if (client.getLocalPlayer() != null && client.getLocalPlayer().hasSpotAnim(SpotanimID.SPECIAL_DUAL_MACUAHUITL_SPOTANIM))
|
||||
{
|
||||
return curSpeed - 1;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Attacking;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.gameval.AnimationID;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
|
||||
@Slf4j
|
||||
public class DoomOfMokhaiotl implements IVariableSpeed
|
||||
{
|
||||
private static final Set<Integer> DOOM_REGION_IDS = new ImmutableSet.Builder<Integer>()
|
||||
.add(5269)
|
||||
.add(13668)
|
||||
.add(14180)
|
||||
.build();
|
||||
|
||||
private static final Set<Integer> COOLDOWN_OVERWRITES_IDS = new ImmutableSet.Builder<Integer>()
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY)
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY_GIANT_MAGE)
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY_GIANT_RANGE)
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY_MAGE)
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY_RANGE)
|
||||
.add(NpcID.DOM_DEMONIC_ENERGY_MELEE)
|
||||
.add(NpcID.DOM_SHOCKWAVE_PATH_NODE)
|
||||
.build();
|
||||
|
||||
private static final Set<Integer> NO_COOLDOWN_WEAPON = new ImmutableSet.Builder<Integer>()
|
||||
.add(ItemID.SILVERLIGHT)
|
||||
.add(ItemID.DARKLIGHT)
|
||||
.add(ItemID.ARCLIGHT)
|
||||
.add(ItemID.EMBERLIGHT)
|
||||
.add(ItemID.BONE_CLAWS)
|
||||
.add(ItemID.SCORCHING_BOW)
|
||||
.add(ItemID.HOLY_WATER)
|
||||
.add(ItemID.EYE_OF_AYAK)
|
||||
.build();
|
||||
|
||||
private final TickCount tickCount;
|
||||
private int larvaeConsumed = -1;
|
||||
private int shieldConsumed = -1;
|
||||
|
||||
public DoomOfMokhaiotl(final TickCount tc)
|
||||
{
|
||||
this.tickCount = tc;
|
||||
}
|
||||
|
||||
public boolean onRender(final Client client, final ItemManager itemManager, final Spellbook spellbook)
|
||||
{
|
||||
if (!CombatUtils.isInRegionId(client, DOOM_REGION_IDS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final var atk = Attacking.playerAttack(client);
|
||||
final AnimationData anim = AnimationData.fromId(atk.getAnimationId());
|
||||
if (anim == null || atk.getTarget() == null || !(atk.getTarget() instanceof NPC) || anim.isBlockListAnimation())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final NPC npc = (NPC) atk.getTarget();
|
||||
final int npcId = npc.getId();
|
||||
if (COOLDOWN_OVERWRITES_IDS.contains(npcId))
|
||||
{
|
||||
if (tickCount.isWithinNTicks(larvaeConsumed, 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final int weaponId = CombatUtils.getWeaponId(client);
|
||||
final boolean isDemonbaneSpell = spellbook == Spellbook.ARCEUUS && AnimationData.isManualCasting(anim) && anim == AnimationData.MAGIC_ARCEUUS_DEMONBANE;
|
||||
if (NO_COOLDOWN_WEAPON.contains(weaponId) || isDemonbaneSpell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
larvaeConsumed = tickCount.get();
|
||||
return true;
|
||||
}
|
||||
else if (npcId == NpcID.DOM_BOSS)
|
||||
{
|
||||
if (tickCount.isWithinNTicks(shieldConsumed, 30))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final int animId = npc.getAnimation();
|
||||
if (animId == AnimationID.DOM_BEAM_CHARGE_LOOP || animId == AnimationID.DOM_BEAM_CHARGE)
|
||||
{
|
||||
if (CombatUtils.getAttackType(client) != null && CombatUtils.getAttackType(client).IsMelee())
|
||||
{
|
||||
shieldConsumed = tickCount.get();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
final boolean inDoom = CombatUtils.isInRegionId(client, DOOM_REGION_IDS);
|
||||
if (inDoom && COOLDOWN_OVERWRITES_IDS.contains(targetId))
|
||||
{
|
||||
final int weaponId = CombatUtils.getWeaponId(client);
|
||||
final boolean isDemonbaneSpell = spellbook == Spellbook.ARCEUUS && AnimationData.isManualCasting(curAnimation) && curAnimation == AnimationData.MAGIC_ARCEUUS_DEMONBANE;
|
||||
if (NO_COOLDOWN_WEAPON.contains(weaponId) || isDemonbaneSpell)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
|
||||
public class EyeOfAyak implements IVariableSpeed
|
||||
{
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
if (curAnimation == AnimationData.MAGIC_EYE_OF_AYAK_SPEC)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.IStateTracker;
|
||||
import net.runelite.api.Client;
|
||||
|
||||
public interface IVariableSpeed extends IStateTracker
|
||||
{
|
||||
int apply(
|
||||
final Client client,
|
||||
final AnimationData curAnimation,
|
||||
final AttackProcedure atkType,
|
||||
final Spellbook spellbook,
|
||||
final int damageDealt,
|
||||
final int lastSpecDelta,
|
||||
final int baseSpeed,
|
||||
final int curSpeed
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.Attacking;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.gameval.AnimationID;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
|
||||
@Slf4j
|
||||
public class MaggotKing
|
||||
{
|
||||
private static final int MAGGOT_KING_REGION_ID = 11645;
|
||||
|
||||
private final TickCount tickCount;
|
||||
private int consumed = -1;
|
||||
|
||||
public MaggotKing(final TickCount tc)
|
||||
{
|
||||
this.tickCount = tc;
|
||||
}
|
||||
|
||||
public boolean onRender(final Client client, final ItemManager itemManager)
|
||||
{
|
||||
if (!CombatUtils.isInRegionId(client, MAGGOT_KING_REGION_ID) || tickCount.isWithinNTicks(consumed, 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final var atk = Attacking.playerAttack(client);
|
||||
final AnimationData anim = AnimationData.fromId(atk.getAnimationId());
|
||||
if (anim == null || atk.getTarget() == null || !(atk.getTarget() instanceof NPC))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final NPC npc = (NPC) atk.getTarget();
|
||||
if (npc.getId() != NpcID.UR_MAGGOT_LARVAE || !anim.isStandardBowAttack()
|
||||
|| npc.getAnimation() != AnimationID.UR_MAGGOT_LARVAE_FLY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
consumed = tickCount.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
public int onChatMessage(final Client client, final String message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (message.contains("The sticky acid hampers your ability to attack!"))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (message.contains("The Maggot King's screech disrupts your concentration!"))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.Yama;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
|
||||
public class PurgingStaffSpec implements IVariableSpeed
|
||||
{
|
||||
private final Yama yama;
|
||||
public NPC lastTarget;
|
||||
|
||||
public PurgingStaffSpec(Yama yama)
|
||||
{
|
||||
this.yama = yama;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
if (this.yama == null || !this.yama.inYamaRegion)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
final NPC target = CombatUtils.getTargetNPC(client);
|
||||
final NPC flare = Yama.isEitherVoidFlare(target, lastTarget);
|
||||
lastTarget = target;
|
||||
if (flare == null)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
|
||||
yama.dealVoidFlareDamage(flare, damageDealt);
|
||||
if (lastSpecDelta != -250 || CombatUtils.getWeaponId(client) != ItemID.PURGING_STAFF || spellbook != Spellbook.ARCEUUS)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
|
||||
if (yama.getVoidFlareDead(flare))
|
||||
{
|
||||
return curSpeed - 2;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.AttackStyle;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.gameval.VarPlayerID;
|
||||
|
||||
public class RapidAttackStyle implements IVariableSpeed
|
||||
{
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final boolean isRapid = client.getVarpValue(VarPlayerID.COM_MODE) == 1;
|
||||
if (atkType == AttackProcedure.MELEE_OR_RANGE && CombatUtils.getAttackStyle(client) == AttackStyle.RANGING && isRapid)
|
||||
{
|
||||
return curSpeed - 1;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
|
||||
public class RedKerisSpec implements IVariableSpeed
|
||||
{
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
if (lastSpecDelta != -750 || curAnimation != AnimationData.MELEE_RED_KERIS_SPEC)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
if (damageDealt > 0)
|
||||
{
|
||||
return curSpeed + 4;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
|
||||
public class RoyalTitans implements IVariableSpeed
|
||||
{
|
||||
private static final int ROYAL_TITANS_REGION_ID = 11669;
|
||||
private static final int HP_FUDGE = 1;
|
||||
private static final int ELEMENTAL_HP = 40 - HP_FUDGE;
|
||||
|
||||
private final Set<NPC> iceElementals = new HashSet<>();
|
||||
private final Set<NPC> fireElementals = new HashSet<>();
|
||||
private boolean removeDead = false;
|
||||
|
||||
private static final Set<AnimationData> ONE_SHOT_SPELLS = new ImmutableSet.Builder<AnimationData>()
|
||||
.add(AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST)
|
||||
.add(AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF)
|
||||
.add(AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF_WALK)
|
||||
.add(AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_WALK)
|
||||
.add(AnimationData.MAGIC_STANDARD_SURGE)
|
||||
.add(AnimationData.MAGIC_STANDARD_SURGE_STAFF)
|
||||
.add(AnimationData.MAGIC_STANDARD_SURGE_STAFF_WALK)
|
||||
.add(AnimationData.MAGIC_STANDARD_WAVE)
|
||||
.add(AnimationData.MAGIC_STANDARD_WAVE_STAFF)
|
||||
.add(AnimationData.MAGIC_STANDARD_WAVE_STAFF_WALK)
|
||||
.add(AnimationData.MAGIC_STANDARD_WAVE_WALK)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
if (earlyExit(client, atkType, damageDealt, spellbook))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
if (spellbook != Spellbook.STANDARD || !isElemental(targetId) || !ONE_SHOT_SPELLS.contains(curAnimation))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
final NPC target = CombatUtils.getTargetNPC(client);
|
||||
if (target == null)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
|
||||
final boolean wieldingTwinflame = CombatUtils.getWeaponId(client) == ItemID.TWINFLAME_STAFF;
|
||||
final int computedDamage = wieldingTwinflame ? damageDealt + ((damageDealt * 4) / 10) : damageDealt;
|
||||
|
||||
if (computedDamage < ELEMENTAL_HP)
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
|
||||
final var set = targetId == NpcID.RT_SUMMON_ELEMENTAL_FIRE ? fireElementals : iceElementals;
|
||||
int count = 1;
|
||||
final var reference = target.getWorldLocation();
|
||||
for (final NPC elemental : set)
|
||||
{
|
||||
if (elemental == target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
final WorldPoint worldLocation = elemental.getWorldLocation();
|
||||
final int distanceTo2D = reference.distanceTo2D(worldLocation);
|
||||
if (distanceTo2D <= 1)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean isTwinflameKillOnSecondProjectile = wieldingTwinflame &&
|
||||
curAnimation == AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF;
|
||||
final int extraHitOffset = isTwinflameKillOnSecondProjectile ? 1 : 0;
|
||||
|
||||
final WorldPoint playerLoc = client.getLocalPlayer().getWorldLocation();
|
||||
final int distance = playerLoc.distanceTo2D(reference);
|
||||
final int hitDelay = 2 + (distance / 3) + extraHitOffset;
|
||||
|
||||
final int remainingAtImpact = Math.max(0, curSpeed - hitDelay);
|
||||
final int remainingAfterReduction = Math.max(0, remainingAtImpact - count);
|
||||
final int finalSpeed = Math.min(curSpeed, hitDelay + remainingAfterReduction);
|
||||
|
||||
removeDead = true;
|
||||
return finalSpeed;
|
||||
}
|
||||
|
||||
private static boolean earlyExit(final Client client, final AttackProcedure atkType, final int damageDealt,
|
||||
final Spellbook spellbook)
|
||||
{
|
||||
return notInRegion(client)
|
||||
|| atkType != AttackProcedure.MANUAL_AUTO_CAST
|
||||
|| damageDealt <= 0
|
||||
|| spellbook != Spellbook.STANDARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameTick(Client client, GameTick tick)
|
||||
{
|
||||
if (removeDead)
|
||||
{
|
||||
boolean removed = iceElementals.removeIf(NPC::isDead);
|
||||
removed |= fireElementals.removeIf(NPC::isDead);
|
||||
if (removed)
|
||||
{
|
||||
removeDead = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNpcSpawned(final Client client, final NpcSpawned npcSpawned)
|
||||
{
|
||||
if (notInRegion(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
final NPC npc = npcSpawned.getNpc();
|
||||
final int id = npc.getId();
|
||||
if (id == NpcID.RT_SUMMON_ELEMENTAL_ICE)
|
||||
{
|
||||
iceElementals.add(npc);
|
||||
}
|
||||
else if (id == NpcID.RT_SUMMON_ELEMENTAL_FIRE)
|
||||
{
|
||||
fireElementals.add(npc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNpcDespawned(final Client client, final NpcDespawned npcDespawned)
|
||||
{
|
||||
if (notInRegion(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
final NPC npc = npcDespawned.getNpc();
|
||||
final int id = npc.getId();
|
||||
if (id == NpcID.RT_SUMMON_ELEMENTAL_ICE)
|
||||
{
|
||||
iceElementals.remove(npc);
|
||||
}
|
||||
else if (id == NpcID.RT_SUMMON_ELEMENTAL_FIRE)
|
||||
{
|
||||
fireElementals.remove(npc);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isElemental(int id)
|
||||
{
|
||||
return id == NpcID.RT_SUMMON_ELEMENTAL_FIRE || id == NpcID.RT_SUMMON_ELEMENTAL_ICE;
|
||||
}
|
||||
|
||||
private static boolean notInRegion(final Client client)
|
||||
{
|
||||
return CombatUtils.getLocalLocation(client).getRegionID() != ROYAL_TITANS_REGION_ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
|
||||
public class Scurrius implements IVariableSpeed
|
||||
{
|
||||
private static final int SCURRIUS_REGION_ID = 13210;
|
||||
private static final int SCURRIUS_MIN_X = 3290;
|
||||
private static final int SCURRIUS_MAX_X = 3307;
|
||||
private static final int SCURRIUS_MIN_Y = 9859;
|
||||
private static final int SCURRIUS_MAX_Y = 9876;
|
||||
|
||||
private static boolean attackingGiantRatWithBoneWeapon(final int equipped, final int regionId, final int x,
|
||||
final int y, final int target)
|
||||
{
|
||||
final boolean correctWeapon = equipped == ItemID.RAT_BONE_STAFF || equipped == ItemID.RAT_BONE_MACE || equipped == ItemID.RAT_BONE_BOW;
|
||||
final boolean correctCoords = x >= SCURRIUS_MIN_X && x <= SCURRIUS_MAX_X && y >= SCURRIUS_MIN_Y && y <= SCURRIUS_MAX_Y;
|
||||
final boolean correctRegion = regionId == SCURRIUS_REGION_ID;
|
||||
final boolean correctEnemy = target == NpcID.RAT_BOSS_GIANT_RAT;
|
||||
return correctWeapon && correctCoords && correctRegion && correctEnemy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final WorldPoint location = CombatUtils.getLocalLocation(client);
|
||||
final int weaponId = CombatUtils.getWeaponId(client);
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
if (attackingGiantRatWithBoneWeapon(weaponId, location.getRegionID(), location.getX(), location.getY(), targetId))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.MarkOfDarkness;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.Yama;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.YamaPhase;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GraphicsObject;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.WorldView;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
@Slf4j
|
||||
public class ShadowCrash
|
||||
{
|
||||
private static final int FIREBALL_ID = 3262;
|
||||
private static final int TILE = 128;
|
||||
|
||||
private static final int HV_GAP_1 = 3;
|
||||
private static final int HV_GAP_2 = 6;
|
||||
private static final int HV_DELTA_1 = HV_GAP_1 * TILE;
|
||||
private static final int HV_DELTA_2 = HV_GAP_2 * TILE;
|
||||
private static final int D_GAP_1 = 2;
|
||||
private static final int D_GAP_2 = 4;
|
||||
private static final int D_DELTA_1 = D_GAP_1 * TILE;
|
||||
private static final int D_DELTA_2 = D_GAP_2 * TILE;
|
||||
|
||||
private final TickCount tickCount;
|
||||
private final Yama yama;
|
||||
private final MarkOfDarkness mod;
|
||||
|
||||
private int consumed = -1;
|
||||
private final Map<LocalPoint, GraphicsObject> fireballs;
|
||||
private ArrayList<FireballLine> lines;
|
||||
private WorldPoint player;
|
||||
|
||||
public ShadowCrash(Yama yama, MarkOfDarkness mod, TickCount tc)
|
||||
{
|
||||
this.yama = yama;
|
||||
this.mod = mod;
|
||||
this.tickCount = tc;
|
||||
this.fireballs = new HashMap<>();
|
||||
this.lines = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int onRender(final Client client, final int attackDelayHoldoffTicks, final boolean isUsingMagic)
|
||||
{
|
||||
if (yama == null || !yama.inYamaRegion || yama.phase() != YamaPhase.P3 || !mod.isActive())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!tickCount.isWithinNTicks(consumed, 2) && shadowCrashSweetSpot(client))
|
||||
{
|
||||
consumed = tickCount.get();
|
||||
if (attackDelayHoldoffTicks <= 1 && isUsingMagic)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean shadowCrashSweetSpot(final Client client)
|
||||
{
|
||||
getState(client);
|
||||
if (lines.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var line : lines)
|
||||
{
|
||||
if (line.isActive())
|
||||
{
|
||||
return line.inSweetSpot(client, player);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void getState(final Client client)
|
||||
{
|
||||
fireballs.clear();
|
||||
lines.clear();
|
||||
final WorldView tlwv = client.getTopLevelWorldView();
|
||||
final Player localPlayer = client.getLocalPlayer();
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final WorldView playerWv = localPlayer.getWorldView();
|
||||
if (tlwv != null)
|
||||
{
|
||||
getFireballs(tlwv);
|
||||
}
|
||||
if (playerWv != null && playerWv != tlwv)
|
||||
{
|
||||
getFireballs(playerWv);
|
||||
}
|
||||
if (fireballs.size() < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player = localPlayer.getWorldLocation();
|
||||
lines = getLines();
|
||||
}
|
||||
|
||||
private void getFireballs(final WorldView wv)
|
||||
{
|
||||
for (GraphicsObject graphicsObject : wv.getGraphicsObjects())
|
||||
{
|
||||
if (graphicsObject.getId() == FIREBALL_ID)
|
||||
{
|
||||
fireballs.put(graphicsObject.getLocation(), graphicsObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<FireballLine> getLines()
|
||||
{
|
||||
final var result = new ArrayList<FireballLine>();
|
||||
|
||||
while (fireballs.size() >= 3)
|
||||
{
|
||||
LocalPoint first = null;
|
||||
final Set<LocalPoint> fireballsLocations = fireballs.keySet();
|
||||
for (var location : fireballsLocations)
|
||||
{
|
||||
if (first == null)
|
||||
{
|
||||
first = location;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.getX() > location.getX())
|
||||
{
|
||||
first = location;
|
||||
}
|
||||
else if (first.getX() == location.getX())
|
||||
{
|
||||
if (first.getY() > location.getY())
|
||||
{
|
||||
first = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (first == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var centre = first.plus(D_DELTA_1, D_DELTA_1);
|
||||
var end = first.plus(D_DELTA_2, D_DELTA_2);
|
||||
if (fireballsLocations.contains(centre) && fireballsLocations.contains(end))
|
||||
{
|
||||
result.add(new FireballLine(LineType.D2, centre, fireballs.get(centre)));
|
||||
removeLine(first, centre, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
centre = first.plus(HV_DELTA_1, 0);
|
||||
end = first.plus(HV_DELTA_2, 0);
|
||||
if (fireballsLocations.contains(centre) && fireballsLocations.contains(end))
|
||||
{
|
||||
result.add(new FireballLine(LineType.H, centre, fireballs.get(centre)));
|
||||
removeLine(first, centre, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
centre = first.plus(0, HV_DELTA_1);
|
||||
end = first.plus(0, HV_DELTA_2);
|
||||
if (fireballsLocations.contains(centre) && fireballsLocations.contains(end))
|
||||
{
|
||||
result.add(new FireballLine(LineType.V, centre, fireballs.get(centre)));
|
||||
removeLine(first, centre, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
centre = first.plus(D_DELTA_1, -D_DELTA_1);
|
||||
end = first.plus(D_DELTA_2, -D_DELTA_2);
|
||||
if (fireballsLocations.contains(centre) && fireballsLocations.contains(end))
|
||||
{
|
||||
result.add(new FireballLine(LineType.D1, centre, fireballs.get(centre)));
|
||||
removeLine(first, centre, end);
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void removeLine(final LocalPoint a, final LocalPoint b, final LocalPoint c)
|
||||
{
|
||||
fireballs.remove(a);
|
||||
fireballs.remove(b);
|
||||
fireballs.remove(c);
|
||||
}
|
||||
|
||||
public static boolean eq(final WorldPoint t, final int dx, final int dy, final WorldPoint other)
|
||||
{
|
||||
if (t == null || other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return t.getX() + dx == other.getX() && t.getY() + dy == other.getY();
|
||||
}
|
||||
|
||||
static class FireballLine
|
||||
{
|
||||
private final LineType type;
|
||||
private final LocalPoint centre;
|
||||
private final GraphicsObject cObject;
|
||||
|
||||
FireballLine(final LineType type, final LocalPoint centre, final GraphicsObject cObject)
|
||||
{
|
||||
this.centre = centre;
|
||||
this.cObject = cObject;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
{
|
||||
final int animationFrame = cObject.getAnimationFrame();
|
||||
return animationFrame >= 30 && animationFrame <= 40;
|
||||
}
|
||||
|
||||
public boolean inSweetSpot(final Client client, final WorldPoint lp)
|
||||
{
|
||||
final WorldPoint wp = WorldPoint.fromLocal(client, centre);
|
||||
switch (this.type)
|
||||
{
|
||||
case V:
|
||||
return eq(wp, 1, 0, lp) || eq(wp, -1, 0, lp);
|
||||
case H:
|
||||
return eq(wp, 0, 1, lp) || eq(wp, 0, -1, lp);
|
||||
case D1:
|
||||
return eq(wp, 1, 1, lp) || eq(wp, -1, -1, lp);
|
||||
case D2:
|
||||
return eq(wp, -1, 1, lp) || eq(wp, 1, -1, lp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum LineType
|
||||
{
|
||||
V, H, D1, D2
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.AttackType;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
|
||||
public class TombsOfAmascut implements IVariableSpeed
|
||||
{
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
final AttackType attkType = CombatUtils.getAttackType(client);
|
||||
if (targetId == NpcID.WARDENS_P3_ORB_BLUE && attkType != null && attkType.IsMelee())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.AttackType;
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.example.essentialsplus.helpers.combat.WeaponType;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
import net.runelite.api.gameval.SpotanimID;
|
||||
|
||||
public class TormentedDemons implements IVariableSpeed
|
||||
{
|
||||
private final TickCount tickCount;
|
||||
private final Map<NPC, DemonData> tormentedDemons = new HashMap<>();
|
||||
|
||||
public TormentedDemons(TickCount tc)
|
||||
{
|
||||
this.tickCount = tc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
|
||||
final int curSpeed)
|
||||
{
|
||||
final int targetId = CombatUtils.getTargetId(client);
|
||||
if (!isTormentedDemon(targetId))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
final NPC target = CombatUtils.getTargetNPC(client);
|
||||
if (!tormentedDemons.containsKey(target))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
final DemonData targetDemon = tormentedDemons.get(target);
|
||||
if (!targetDemon.isVulnerable(tickCount.get()))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
if (targetDemon.vulnConsumed(tickCount.get()))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
switch (atkType)
|
||||
{
|
||||
case POWERED_STAVE:
|
||||
return curSpeed;
|
||||
case MANUAL_AUTO_CAST:
|
||||
break;
|
||||
case MELEE_OR_RANGE:
|
||||
final WeaponType wep = CombatUtils.getWeaponType(client);
|
||||
final AttackType attkType = CombatUtils.getAttackType(client);
|
||||
if (wep != WeaponType.HEAVY_RANGED && (attkType == null || attkType != AttackType.CRUSH))
|
||||
{
|
||||
return curSpeed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (curSpeed > 4)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return curSpeed;
|
||||
}
|
||||
|
||||
private static boolean isTormentedDemon(int targetId)
|
||||
{
|
||||
return targetId == NpcID.TORMENTED_DEMON_1 || targetId == NpcID.TORMENTED_DEMON_2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameTick(Client client, GameTick tick)
|
||||
{
|
||||
for (final Map.Entry<NPC, DemonData> td : tormentedDemons.entrySet())
|
||||
{
|
||||
final boolean isVulnerable = td.getKey().hasSpotAnim(SpotanimID.LUC2_UNDEAD_DEMON_EXPLOSION_FIRE_SPOT);
|
||||
td.getValue().update(tickCount.get(), isVulnerable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNpcSpawned(final Client client, final NpcSpawned npcSpawned)
|
||||
{
|
||||
final NPC npc = npcSpawned.getNpc();
|
||||
maybeInsertDemon(npc);
|
||||
}
|
||||
|
||||
private void maybeInsertDemon(final NPC npc)
|
||||
{
|
||||
if (isTormentedDemon(npc.getId()))
|
||||
{
|
||||
final boolean isVulnerable = npc.hasSpotAnim(SpotanimID.LUC2_UNDEAD_DEMON_EXPLOSION_FIRE_SPOT);
|
||||
tormentedDemons.put(npc, new DemonData(tickCount.get(), isVulnerable));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNpcDespawned(final Client client, final NpcDespawned npcDespawned)
|
||||
{
|
||||
final NPC npc = npcDespawned.getNpc();
|
||||
if (isTormentedDemon(npc.getId()))
|
||||
{
|
||||
tormentedDemons.remove(npc);
|
||||
}
|
||||
}
|
||||
|
||||
static class DemonData
|
||||
{
|
||||
private static final int VULN_TICKS_AFTER_END = 10;
|
||||
private Integer vulnerableStart;
|
||||
private Integer vulnerableFinish;
|
||||
private int attacked;
|
||||
|
||||
DemonData(int tick, boolean vuln)
|
||||
{
|
||||
this.update(tick, vuln);
|
||||
this.attacked = -1;
|
||||
}
|
||||
|
||||
void update(int tick, boolean vuln)
|
||||
{
|
||||
if (vuln && this.vulnerableStart == null)
|
||||
{
|
||||
this.vulnerableStart = tick;
|
||||
this.vulnerableFinish = tick;
|
||||
}
|
||||
else if (vuln && this.vulnerableStart != null)
|
||||
{
|
||||
this.vulnerableFinish = tick;
|
||||
}
|
||||
|
||||
if (!vuln)
|
||||
{
|
||||
this.vulnerableStart = null;
|
||||
}
|
||||
if (this.attacked != -1 && this.attacked + 1 >= tick)
|
||||
{
|
||||
this.attacked = -1;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isVulnerable(int tick)
|
||||
{
|
||||
if (this.vulnerableFinish == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (this.vulnerableFinish + VULN_TICKS_AFTER_END) > tick;
|
||||
}
|
||||
|
||||
boolean vulnConsumed(int tick)
|
||||
{
|
||||
if (this.attacked == tick || this.attacked == -1)
|
||||
{
|
||||
this.consumeVuln(tick);
|
||||
return false;
|
||||
}
|
||||
else if (this.attacked > tick + VULN_TICKS_AFTER_END)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.consumeVuln(tick);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void consumeVuln(int tick)
|
||||
{
|
||||
this.attacked = tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.AnimationData;
|
||||
import com.example.essentialsplus.helpers.combat.AttackProcedure;
|
||||
import com.example.essentialsplus.helpers.combat.Spellbook;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.IStateTracker;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.MarkOfDarkness;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.TickCount;
|
||||
import com.example.essentialsplus.helpers.combat.variablespeed.state.Yama;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
|
||||
public class VariableSpeed
|
||||
{
|
||||
private final TickCount tickCount;
|
||||
private final Yama yama;
|
||||
private final MarkOfDarkness markOfDarkness;
|
||||
|
||||
public final ShadowCrash shadowCrash;
|
||||
public final MaggotKing maggotKing;
|
||||
public final DoomOfMokhaiotl doomOfMokhaiotl;
|
||||
|
||||
private final IStateTracker[] toTrack;
|
||||
private final IVariableSpeed[] toApply;
|
||||
|
||||
public VariableSpeed(TickCount tc)
|
||||
{
|
||||
this.tickCount = tc;
|
||||
this.yama = new Yama();
|
||||
this.markOfDarkness = new MarkOfDarkness();
|
||||
this.shadowCrash = new ShadowCrash(yama, markOfDarkness, tc);
|
||||
this.maggotKing = new MaggotKing(tc);
|
||||
this.doomOfMokhaiotl = new DoomOfMokhaiotl(tc);
|
||||
|
||||
this.toTrack = new IStateTracker[]{
|
||||
tc,
|
||||
yama,
|
||||
markOfDarkness
|
||||
};
|
||||
|
||||
this.toApply = new IVariableSpeed[]{
|
||||
new BloodMoonSet(),
|
||||
new RapidAttackStyle(),
|
||||
new RedKerisSpec(),
|
||||
new PurgingStaffSpec(yama),
|
||||
new EyeOfAyak(),
|
||||
new TormentedDemons(tc),
|
||||
new RoyalTitans(),
|
||||
new Amoxliatl(),
|
||||
new Scurrius(),
|
||||
new TombsOfAmascut(),
|
||||
doomOfMokhaiotl
|
||||
};
|
||||
}
|
||||
|
||||
public int compute(final Client client, final AnimationData curAnimation, final AttackProcedure atkType,
|
||||
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed)
|
||||
{
|
||||
int newSpeed = baseSpeed;
|
||||
for (final IVariableSpeed i : toApply)
|
||||
{
|
||||
newSpeed = i.apply(client, curAnimation, atkType, spellbook, damageDealt, lastSpecDelta, baseSpeed, newSpeed);
|
||||
}
|
||||
return newSpeed;
|
||||
}
|
||||
|
||||
public void onGameTick(final Client client, final GameTick tick)
|
||||
{
|
||||
for (final IStateTracker i : toTrack)
|
||||
{
|
||||
i.onGameTick(client, tick);
|
||||
}
|
||||
for (final IStateTracker i : toApply)
|
||||
{
|
||||
i.onGameTick(client, tick);
|
||||
}
|
||||
}
|
||||
|
||||
public void onChatMessage(final Client client, final ChatMessage event)
|
||||
{
|
||||
for (final IStateTracker i : toTrack)
|
||||
{
|
||||
i.onChatMessage(client, event);
|
||||
}
|
||||
for (final IStateTracker i : toApply)
|
||||
{
|
||||
i.onChatMessage(client, event);
|
||||
}
|
||||
}
|
||||
|
||||
public void onNpcSpawned(final Client client, final NpcSpawned npcSpawned)
|
||||
{
|
||||
for (final IStateTracker i : toTrack)
|
||||
{
|
||||
i.onNpcSpawned(client, npcSpawned);
|
||||
}
|
||||
for (final IStateTracker i : toApply)
|
||||
{
|
||||
i.onNpcSpawned(client, npcSpawned);
|
||||
}
|
||||
}
|
||||
|
||||
public void onNpcDespawned(final Client client, final NpcDespawned npcDespawned)
|
||||
{
|
||||
for (final IStateTracker i : toTrack)
|
||||
{
|
||||
i.onNpcDespawned(client, npcDespawned);
|
||||
}
|
||||
for (final IStateTracker i : toApply)
|
||||
{
|
||||
i.onNpcDespawned(client, npcDespawned);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed.state;
|
||||
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
|
||||
public interface IStateTracker
|
||||
{
|
||||
default void onGameTick(final Client client, final GameTick tick)
|
||||
{
|
||||
}
|
||||
|
||||
default void onChatMessage(final Client client, final ChatMessage event)
|
||||
{
|
||||
}
|
||||
|
||||
default void onNpcSpawned(final Client client, final NpcSpawned npcSpawned)
|
||||
{
|
||||
}
|
||||
|
||||
default void onNpcDespawned(final Client client, final NpcDespawned npcDespawned)
|
||||
{
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed.state;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.gameval.ItemID;
|
||||
import net.runelite.client.util.RSTimeUnit;
|
||||
|
||||
public class MarkOfDarkness implements IStateTracker
|
||||
{
|
||||
private static final String MARK_OF_DARKNESS_MESSAGE = "You have placed a Mark of Darkness upon yourself.</col>";
|
||||
|
||||
private Instant modStartTime = Instant.now();
|
||||
private Instant modEndTime = Instant.now();
|
||||
|
||||
@Override
|
||||
public void onChatMessage(Client client, ChatMessage event)
|
||||
{
|
||||
final String message = event.getMessage();
|
||||
if (message != null && message.endsWith(MARK_OF_DARKNESS_MESSAGE))
|
||||
{
|
||||
final Duration duration = getMarkOfDarknessDuration(client);
|
||||
this.modStartTime = Instant.now();
|
||||
this.modEndTime = modStartTime.plus(duration);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
{
|
||||
final Instant n = Instant.now();
|
||||
return this.modStartTime.isBefore(n) && this.modEndTime.isAfter(n);
|
||||
}
|
||||
|
||||
private static Duration getMarkOfDarknessDuration(Client client)
|
||||
{
|
||||
final int magicLevel = client.getRealSkillLevel(Skill.MAGIC);
|
||||
final Duration markOfDarknessDuration = Duration.of((long) magicLevel * 3, RSTimeUnit.GAME_TICKS);
|
||||
if (CombatUtils.getWeaponId(client) == ItemID.PURGING_STAFF)
|
||||
{
|
||||
return markOfDarknessDuration.multipliedBy(5);
|
||||
}
|
||||
return markOfDarknessDuration;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed.state;
|
||||
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.GameTick;
|
||||
|
||||
public class TickCount implements IStateTracker
|
||||
{
|
||||
private int tickCount = 0;
|
||||
|
||||
public int get()
|
||||
{
|
||||
return tickCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameTick(Client client, GameTick tick)
|
||||
{
|
||||
tickCount++;
|
||||
}
|
||||
|
||||
public boolean isWithinNTicks(int toCheckAgainst, int n)
|
||||
{
|
||||
return this.tickCount <= toCheckAgainst + n && this.tickCount >= toCheckAgainst;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
tickCount = 0;
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed.state;
|
||||
|
||||
import com.example.essentialsplus.helpers.combat.CombatUtils;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.NonNull;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.api.gameval.NpcID;
|
||||
|
||||
public class Yama implements IStateTracker
|
||||
{
|
||||
private static final int HP_FUDGE = 2;
|
||||
private static final int VOID_FLARE_HP_P1_P2 = 140 - HP_FUDGE;
|
||||
private static final int VOID_FLARE_HP_P3 = 71 - HP_FUDGE;
|
||||
private static final int YAMA_REGION_ID = 6045;
|
||||
private static final int YAMA_PHASE_TRANSITION_ANIMATION_ID = 12147;
|
||||
|
||||
public YamaData yama;
|
||||
public boolean inYamaRegion;
|
||||
public NPC lastTarget;
|
||||
|
||||
@Override
|
||||
public void onGameTick(Client client, GameTick tick)
|
||||
{
|
||||
inYamaRegion = CombatUtils.isInRegionId(client, YAMA_REGION_ID);
|
||||
if (!inYamaRegion)
|
||||
{
|
||||
yama = null;
|
||||
return;
|
||||
}
|
||||
if (yama != null)
|
||||
{
|
||||
yama.determineYamaPhase();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChatMessage(Client client, ChatMessage event)
|
||||
{
|
||||
if (!inYamaRegion || yama == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (event.getMessage().startsWith("Your Yama success count is:"))
|
||||
{
|
||||
yama.killed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNpcSpawned(final Client client, final NpcSpawned npcSpawned)
|
||||
{
|
||||
if (!inYamaRegion || yama != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final NPC npc = npcSpawned.getNpc();
|
||||
if (npc.getId() == NpcID.YAMA)
|
||||
{
|
||||
yama = new YamaData(npc);
|
||||
}
|
||||
}
|
||||
|
||||
public static NPC isEitherVoidFlare(NPC a, NPC b)
|
||||
{
|
||||
if (a != null && a.getId() == NpcID.YAMA_VOIDFLARE)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
if (b != null && b.getId() == NpcID.YAMA_VOIDFLARE)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void dealVoidFlareDamage(NPC target, int damageDealt)
|
||||
{
|
||||
if (yama == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.yama.dealVoidFlareDamage(target, damageDealt);
|
||||
}
|
||||
|
||||
public boolean getVoidFlareDead(NPC target)
|
||||
{
|
||||
if (yama == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this.yama.getVoidFlareDead(target);
|
||||
}
|
||||
|
||||
public YamaPhase phase()
|
||||
{
|
||||
if (yama == null)
|
||||
{
|
||||
return YamaPhase.P1;
|
||||
}
|
||||
return this.yama.phase;
|
||||
}
|
||||
|
||||
public static class YamaData
|
||||
{
|
||||
@NonNull
|
||||
private final NPC yama;
|
||||
private YamaPhase phase;
|
||||
private int phaseChangeCooldown;
|
||||
private final Map<NPC, Integer> voidFlares;
|
||||
|
||||
YamaData(@NonNull NPC yama)
|
||||
{
|
||||
this.yama = yama;
|
||||
this.phase = YamaPhase.P1;
|
||||
this.phaseChangeCooldown = 0;
|
||||
this.voidFlares = new HashMap<>();
|
||||
}
|
||||
|
||||
public boolean getVoidFlareDead(NPC target)
|
||||
{
|
||||
if (!this.voidFlares.containsKey(target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this.voidFlares.get(target) <= 0;
|
||||
}
|
||||
|
||||
public void dealVoidFlareDamage(NPC target, int damageDealt)
|
||||
{
|
||||
if (this.voidFlares.containsKey(target))
|
||||
{
|
||||
this.voidFlares.put(target, this.voidFlares.get(target) - damageDealt);
|
||||
}
|
||||
else
|
||||
{
|
||||
final int hp = this.getVoidFlareHp() - damageDealt;
|
||||
this.voidFlares.put(target, hp);
|
||||
}
|
||||
}
|
||||
|
||||
private void determineYamaPhase()
|
||||
{
|
||||
if (phaseChangeCooldown == 0 && this.yama.getAnimation() == YAMA_PHASE_TRANSITION_ANIMATION_ID)
|
||||
{
|
||||
this.phaseChangeCooldown = 20;
|
||||
this.phase = this.phase.nextPhase();
|
||||
}
|
||||
if (this.phaseChangeCooldown > 0)
|
||||
{
|
||||
this.phaseChangeCooldown--;
|
||||
}
|
||||
}
|
||||
|
||||
private int getVoidFlareHp()
|
||||
{
|
||||
switch (this.phase)
|
||||
{
|
||||
case P1:
|
||||
case P2:
|
||||
return VOID_FLARE_HP_P1_P2;
|
||||
default:
|
||||
return VOID_FLARE_HP_P3;
|
||||
}
|
||||
}
|
||||
|
||||
private void killed()
|
||||
{
|
||||
this.phase = YamaPhase.P1;
|
||||
this.voidFlares.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.example.essentialsplus.helpers.combat.variablespeed.state;
|
||||
|
||||
public enum YamaPhase
|
||||
{
|
||||
P1, P2, P3;
|
||||
|
||||
public YamaPhase nextPhase()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case P1:
|
||||
return P2;
|
||||
case P2:
|
||||
return P3;
|
||||
case P3:
|
||||
return P3;
|
||||
}
|
||||
return P1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user