RuneHive-Tarnish
Neural OSRS Enhancement Framework
Loading...
Searching...
No Matches
CombatUtil.java
1package com.osroyale.game.world.entity.combat;
2
3import com.osroyale.content.activity.Activity;
4import com.osroyale.content.activity.ActivityType;
5import com.osroyale.content.lms.LMSGame;
6import com.osroyale.content.skill.impl.slayer.SlayerTask;
7import com.osroyale.game.Animation;
8import com.osroyale.game.Projectile;
9import com.osroyale.game.UpdatePriority;
10import com.osroyale.game.world.World;
11import com.osroyale.game.world.entity.combat.effect.AntifireDetails;
12import com.osroyale.game.world.entity.combat.effect.CombatEffect;
13import com.osroyale.game.world.entity.combat.effect.CombatEffectType;
14import com.osroyale.game.world.entity.combat.hit.CombatHit;
15import com.osroyale.game.world.entity.combat.hit.Hit;
16import com.osroyale.game.world.entity.combat.hit.HitIcon;
17import com.osroyale.game.world.entity.combat.hit.Hitsplat;
18import com.osroyale.game.world.entity.combat.projectile.CombatProjectile;
19import com.osroyale.game.world.entity.combat.strategy.CombatStrategy;
20import com.osroyale.game.world.entity.mob.Mob;
21import com.osroyale.game.world.entity.mob.data.PacketType;
22import com.osroyale.game.world.entity.mob.npc.Npc;
23import com.osroyale.game.world.entity.mob.player.Player;
24import com.osroyale.game.world.entity.mob.prayer.Prayer;
25import com.osroyale.game.world.items.Item;
26import com.osroyale.game.world.items.containers.equipment.Equipment;
27import com.osroyale.game.world.position.Area;
28import com.osroyale.net.packet.out.SendMessage;
29import com.osroyale.util.RandomUtils;
30import com.osroyale.util.Utility;
31
32import java.util.List;
33import java.util.function.Consumer;
34
76
77public final class CombatUtil {
78
84 private CombatUtil() {
85 throw new UnsupportedOperationException("This class cannot be instantiated!");
86 }
87
95 public static void areaAction(Mob mob, Consumer<Mob> action) {
96 action.accept(mob);
97 areaAction(mob, 3 * 3, 1, action);
98 }
99
106 public static void areaAction(Mob mob, int max, int distance, Consumer<Mob> action) {
107 if (!Area.inMulti(mob)) {
108 return;
109 }
110
111 int added = 0;
112 List<Player> players = World.getRegions().getLocalPlayers(mob);
113 players.sort((first, second) -> {
114 int firstD = Utility.getDistance(first, mob);
115 int secondD = Utility.getDistance(second, mob);
116 return firstD - secondD;
117 });
118
119 for (Player other : players) {
120 if (other == null) continue;
121 if (other.instance != mob.instance) continue;
122 if (!Utility.withinViewingDistance(other, mob, distance)) continue;
123 if (other.equals(mob)) continue;
124 if (other.getCurrentHealth() <= 0 || other.isDead()) continue;
125 if (!Area.inMulti(other)) continue;
126 if (mob.isPlayer() && other.isPlayer() && (!Area.inWilderness(mob) || !Area.inWilderness(other)))
127 continue;
128 action.accept(other);
129 if (++added == max) return;
130 }
131
132 List<Npc> npcs = World.getRegions().getLocalNpcs(mob);
133 npcs.sort((first, second) -> {
134 int firstD = Utility.getDistance(first, mob);
135 int secondD = Utility.getDistance(second, mob);
136 return firstD - secondD;
137 });
138
139 for (Npc other : npcs) {
140 if (other == null) continue;
141 if (other.instance != mob.instance) continue;
142 if (!Utility.withinViewingDistance(other, mob, distance)) continue;
143 if (other.equals(mob)) continue;
144 if (other.getCurrentHealth() <= 0 || other.isDead()) continue;
145 if (!Area.inMulti(other)) continue;
146 if (!other.definition.isAttackable()) continue;
147 action.accept(other);
148 if (++added == max) return;
149 }
150 }
151
160 public static int getHitDelay(final Mob attacker, final Mob defender, final CombatType type) {
161 if (CombatType.MELEE.equals(type)) return 0;
162
163 final CombatStrategy<? super Mob> strategy = attacker.getStrategy();
164 if (strategy != null) {
165 final CombatProjectile combatProjectile = strategy.getCombatProjectile();
166 if (combatProjectile != null) {
167 final int serverTicks = combatProjectile.getServerTicks();
168 if (serverTicks > 0) {
169 return serverTicks;
170 }
171 }
172 }
173 return getOldHitDelay(attacker, defender, type);
174 }
175
176 private static int getOldHitDelay(final Mob attacker, final Mob defender, final CombatType type) {
177 final int distance = Math.min(10, Utility.getDistance(attacker, defender));
178 return switch (type) {
179 default -> 0;
180 case RANGED -> Projectile.RANGED_DELAYS[distance] - 1;
181 case MAGIC -> Projectile.MAGIC_DELAYS[distance] - 1;
182 };
183 }
184
191 public static int getHitsplatDelay(CombatType type) {
192 return type.getHitsplatDelay();
193 }
194
195 static boolean validateMobs(Mob attacker, Mob defender) {
196 if (!validate(attacker) || !validate(defender)) {
197 attacker.getCombat().reset();
198 return false;
199 }
200
201 if (attacker.instance != defender.instance) {
202 attacker.getCombat().reset();
203 return false;
204 }
205
206 if (!canAttack(attacker, defender)) {
207 attacker.getCombat().reset();
208 return false;
209 }
210 return true;
211 }
212
213 static boolean validate(Mob attacker, Mob defender) {
214 if (!validate(attacker) || !validate(defender)) {
215 attacker.getCombat().reset();
216 return false;
217 }
218
219 if (attacker.instance != defender.instance) {
220 attacker.getCombat().reset();
221 return false;
222 }
223
224 if (!canBasicAttack(attacker, defender)) {
225 attacker.getCombat().reset();
226 return false;
227 }
228 return true;
229 }
230
237 public static boolean effect(Mob mob, CombatEffectType effect) {
238 return CombatEffect.EFFECTS.get(effect).start(mob);
239 }
240
247 public static boolean cancelEffect(Mob mob, CombatEffectType effect) {
248 return CombatEffect.EFFECTS.get(effect).removeOn(mob);
249 }
250
251 public static boolean canAttack(Mob attacker, Mob defender) {
252 if (attacker.isPlayer())
253 return canAttack(attacker.getPlayer(), defender);
254 return canAttack(attacker.getNpc(), defender);
255 }
256
257 private static boolean canAttack(Player attacker, Mob defender) {
258
259
260 if (defender.isNpc() && !SlayerTask.canAttack(attacker, defender.getName())) {
261 attacker.send(new SendMessage("You do not meet the slayer requirements to attack this npc!"));
262 return false;
263 }
264 if (attacker.equals(defender)) {
265 //attacker.send(new SendMessage("You can't attack yourself!"));
266 return false;
267 }
268 if (defender.isNpc() && defender.getNpc().owner != null && !attacker.equals(defender.getNpc().owner)) {
269 attacker.send(new SendMessage("You can't attack this npc!"));
270 return false;
271 }
272
273 if (attacker.getCombat().isUnderAttack() && !attacker.getCombat().isUnderAttackBy(defender)) {
274 if (!Area.inMulti(attacker) || !Area.inMulti(defender)) {
275 attacker.send(new SendMessage("You are already under attack!"));
276 return false;
277 }
278 }
279
280 if (defender.getCombat().isUnderAttack() && !defender.getCombat().isUnderAttackBy(attacker)) {
281 if (!Area.inMulti(attacker) || !Area.inMulti(defender)) {
282 if (defender.isPlayer()) {
283 attacker.send(new SendMessage(defender.getName() + " is currently in combat and can not be attacked."));
284 } else {
285 attacker.send(new SendMessage("This monster is already under attack!"));
286 }
287 return false;
288 }
289 }
290 if (defender.isPlayer()) {
291 if (attacker.locking.locked(PacketType.COMBAT)) {
292 return false;
293 }
294
295 if (LMSGame.inGameArea(attacker) && LMSGame.canAttack(attacker, defender.getPlayer())) {
296 return true;
297 }
298
299 if (Activity.evaluate(attacker, activity -> defender.activity == activity) && attacker.inActivity(ActivityType.DUEL_ARENA)) {
300 return true;
301 }
302
303/*
304 if (Area.inEventArena(attacker) && Area.inEventArena(defender)) {
305 return true;
306 }
307*/
308
309 int difference = Math.abs(attacker.skills.getCombatLevel() - defender.skills.getCombatLevel());
310
311 if (attacker.pvpInstance) {
312 if (!defender.getPlayer().pvpInstance) {
313 attacker.message(defender.getName() + " is not in a PvP instance.");
314 return false;
315 }
316 if (!Area.inPvP(attacker) && !attacker.hasPvPTimer) {
317 attacker.message("You must be in a PvP zone to attack " + defender.getName() + "!");
318 return false;
319 }
320
321 if (!Area.inPvP(defender) && !defender.getPlayer().hasPvPTimer) {
322 attacker.message(defender.getName() + " must be in a PvP zone for you to attack!");
323 return false;
324 }
325
326 if (difference > 10) {
327 if (!Area.inDuelObsticleArena(attacker)) {
328 attacker.message("Your combat level difference is too great!");
329 return false;
330 }
331 }
332 return true;
333 }
334
335 if (difference > attacker.wilderness) {
336 if (!Area.inDuelObsticleArena(attacker)) {
337 attacker.send(new SendMessage("Your combat level difference is too great!"));
338 return false;
339 }
340 }
341
342 if (!Area.inWilderness(attacker)) {
343 attacker.send(new SendMessage("You need to be in the wilderness to attack " + Utility.formatName(defender.getName()) + "."));
344 return false;
345 }
346
347 if (!Area.inWilderness(defender)) {
348 attacker.send(new SendMessage(Utility.formatName(defender.getName()) + " must be in the wilderness for you to attack."));
349 return false;
350 }
351 }
352 return true;
353 }
354
355 private static boolean canAttack(Npc attacker, Mob defender) {
356 if (attacker.equals(defender)) {
357 return false;
358 }
359 if (defender.isNpc() && defender.getNpc().owner != null && !defender.getNpc().owner.equals(attacker)) {
360 return false;
361 }
362 if (attacker.getCombat().isUnderAttack() && !attacker.getCombat().isUnderAttackBy(defender)) {
363 if (!Area.inMulti(attacker) || !Area.inMulti(defender)) {
364 return false;
365 }
366 }
367 if (defender.getCombat().isUnderAttack() && !defender.getCombat().isUnderAttackBy(attacker)) {
368 return Area.inMulti(attacker) && Area.inMulti(defender);
369 }
370 return true;
371 }
372
373 public static boolean canBasicAttack(Mob attacker, Mob defender) {
374 if (attacker.equals(defender)) {
375 return false;
376 }
377 if (defender.isNpc() && defender.getNpc().owner != null && !attacker.equals(defender.getNpc().owner)) {
378 return false;
379 }
380 if (Activity.evaluate(attacker, activity -> defender.activity == activity) && attacker.inActivity(ActivityType.DUEL_ARENA)) {
381 return true;
382 }
383 if (attacker.getCombat().isUnderAttack() && !attacker.getCombat().isUnderAttackBy(defender)) {
384 if (!Area.inMulti(attacker) || !Area.inMulti(defender)) {
385 return false;
386 }
387 }
388 if (defender.getCombat().isUnderAttack() && !defender.getCombat().isUnderAttackBy(attacker)) {
389 if (!Area.inMulti(attacker) || !Area.inMulti(defender)) {
390 return false;
391 }
392 }
393 if (attacker.isPlayer() && defender.isPlayer()) {
394 int difference = Math.abs(attacker.skills.getCombatLevel() - defender.skills.getCombatLevel());
395
396 if (attacker.getPlayer().pvpInstance || defender.getPlayer().pvpInstance) {
397 if (!defender.getPlayer().pvpInstance) {
398 return false;
399 }
400 if (!attacker.getPlayer().pvpInstance) {
401 return false;
402 }
403 if (!Area.inPvP(attacker)) {
404 return false;
405 }
406 if (!Area.inPvP(defender)) {
407 return false;
408 }
409 return difference <= 10;
410 }
411
412
413 if (difference > attacker.getPlayer().wilderness) {
414 return false;
415 }
416 if (!Area.inWilderness(attacker)) {
417 return false;
418 }
419 return Area.inWilderness(defender);
420 }
421 return true;
422 }
423
424 private static boolean validate(Mob mob) {
425 return mob != null && !mob.isDead() && mob.isVisible() && mob.isValid() && !mob.teleporting && !mob.inTeleport;
426 }
427
428 public static Animation getBlockAnimation(Mob mob) {
429 int animation = 404;
430 if (mob.isPlayer()) {
431 final var shieldOverride = mob.getPlayer().overrides.hasOverride(Equipment.SHIELD_SLOT);
432 if (mob.getPlayer().equipment.hasShield() || shieldOverride) {
433 Item shield = shieldOverride ? mob.getPlayer().overrides.get(Equipment.SHIELD_SLOT) : mob.getPlayer().equipment.getShield();
434 animation = shield.getBlockAnimation().orElse(424);
435 } else if (mob.isPlayer()) {
436 final var weaponOverride = mob.getPlayer().overrides.hasOverride(Equipment.WEAPON_SLOT);
437 if (mob.getPlayer().equipment.hasWeapon() || weaponOverride) {
438 Item weapon = weaponOverride ? mob.getPlayer().overrides.get(Equipment.WEAPON_SLOT) : mob.getPlayer().equipment.getWeapon();
439 animation = weapon.getBlockAnimation().orElse(424);
440 } else {
441 animation = 404;//TODO
442 }
443 }
444 } else {
445 Npc npc = mob.getNpc();
446 animation = npc.definition.getBlockAnimation();
447 }
448 int delay = (int) mob.getCombat().lastBlocked.elapsedTime();
449 if (delay < 600)
450 return new Animation(animation, delay / 50, UpdatePriority.LOW);
451 return new Animation(animation, UpdatePriority.LOW);
452 }
453
454 public static CombatHit generateDragonfire(Mob attacker, Mob defender, int max, boolean prayer) {
455 int hitDelay = getHitDelay(attacker, defender, CombatType.MAGIC);
456 int hitsplatDelay = 1;
457 return generateDragonfire(attacker, defender, max, hitDelay, hitsplatDelay, prayer);
458 }
459
460 public static CombatHit generateDragonfire(Mob attacker, Mob defender, int max, int hitDelay, int hitsplatDelay, boolean prayer) {
461 int damage;
462
463 if (defender.isPlayer()) {
464 Player player = defender.getPlayer();
465
466 if (Equipment.isWearingDFS(player) && player.dragonfireCharges < 50) {
467 if (player.equipment.getShield().getId() == 11284) {
468 player.equipment.set(Equipment.SHIELD_SLOT, new Item(11283), true);
469 player.equipment.refresh();
470 }
471 player.animate(6695);
472 player.graphic(1164);
473 player.dragonfireCharges++;
474 player.getCombat().setCooldown(5);
475 player.send(new SendMessage("Your dragonfire Shield Absorbs the Dragon breath."));
476 player.face(attacker);
477 damage = 0;
478 } else {
479 prayer &= player.prayer.isActive(Prayer.PROTECT_FROM_MAGIC);
480 boolean shield = player.equipment.containsAny(1540, 11283, 21633);
481 boolean potion = player.getAntifireDetails().isPresent();
482
483 if (shield && potion) {
484 max -= 65;
485 } else if (potion) {
486 AntifireDetails.AntifireType type = player.getAntifireDetails().get().getType();
487 max -= type.getReduction();
488 if (max <= 0) {
489 max = 0;
490 }
491 } else if (shield) {
492 max -= 50;
493 } else if (prayer) {
494 max -= 45;
495 }
496
497 if (max > 0) {
498 damage = RandomUtils.inclusive(max);
499 } else {
500 damage = 0;
501 }
502
503 if (damage >= 15) {
504 player.send(new SendMessage("You are horribly burned by the dragonfire!", true));
505 } else if (!shield && !potion && !prayer && damage < 9 && damage > 0) {
506 player.send(new SendMessage("You manage to resist some of the dragonfire.", true));
507 }
508 }
509 } else {
510 damage = max == 0 ? 0 : RandomUtils.inclusive(max);
511 }
512
513 Hit hit = new Hit(damage, Hitsplat.NORMAL, HitIcon.NONE, true);
514 return new CombatHit(hit, hitDelay, hitsplatDelay);
515 }
516
517 public static CombatStrategy<Npc> randomStrategy(CombatStrategy<Npc>[] strategies) {
518 return RandomUtils.random(strategies);
519 }
520
521 @SafeVarargs
522 public static CombatStrategy<Npc>[] createStrategyArray(CombatStrategy<Npc>... strategies) {
523 return strategies;
524 }
525
526 @SafeVarargs
527 public static CombatStrategy<Npc>[] createStrategyArray(CombatStrategy<Npc>[] strategies,
528 CombatStrategy<Npc>... moreStrategies) {
529 final CombatStrategy<Npc>[] array = new CombatStrategy[strategies.length + moreStrategies.length];
530 System.arraycopy(strategies, 0, array, 0, strategies.length);
531 System.arraycopy(moreStrategies, 0, array, strategies.length, moreStrategies.length);
532 return array;
533 }
534
535}
static final int[] RANGED_DELAYS
static final int[] MAGIC_DELAYS
static void areaAction(Mob mob, int max, int distance, Consumer< Mob > action)
static void areaAction(Mob mob, Consumer< Mob > action)
static int getHitDelay(final Mob attacker, final Mob defender, final CombatType type)
static boolean effect(Mob mob, CombatEffectType effect)
static boolean cancelEffect(Mob mob, CombatEffectType effect)
static final Map< CombatEffectType, CombatEffect > EFFECTS
abstract< T extends Mob > CombatStrategy<? super T > getStrategy()
abstract Combat<? extends Mob > getCombat()