package com.example.tests;
import com.frotty27.hrtk.api.annotation.CombatTest;
import com.frotty27.hrtk.api.annotation.HytaleSuite;
import com.frotty27.hrtk.api.annotation.Tag;
import com.frotty27.hrtk.api.annotation.DisplayName;
import com.frotty27.hrtk.api.annotation.Order;
import com.frotty27.hrtk.api.assert_.CombatAssert;
import com.frotty27.hrtk.api.assert_.HytaleAssert;
import com.frotty27.hrtk.api.assert_.StatsAssert;
import com.frotty27.hrtk.api.context.WorldTestContext;
import com.frotty27.hrtk.api.lifecycle.IsolationStrategy;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import com.hypixel.hytale.server.core.modules.entitystats.asset.DefaultEntityStatTypes;
@HytaleSuite(value = "Combat Surface Tests", isolation = IsolationStrategy.DEDICATED_WORLD)
@Tag("combat")
public class CombatSurfaceTests {
@CombatTest
@Order(1)
@DisplayName("Spawned Kweebec is alive with full health")
void spawnedKweebecIsAlive(WorldTestContext ctx) {
// Spawn a Kweebec NPC and allow one tick for initialization.
// After spawning, it should be alive and at maximum health.
Object entity = ctx.spawnNPC("Kweebec_Sapling", 0, 64, 0);
ctx.waitTicks(1);
Object store = ctx.getStore();
StatsAssert.assertAlive(store, entity);
StatsAssert.assertHealthAtMax(store, entity);
}
@CombatTest
@Order(2)
@DisplayName("Damage reduces Kweebec health below maximum")
void damageReducesHealth(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Kweebec_Sapling", 10, 64, 10);
ctx.waitTicks(1);
Object store = ctx.getStore();
var statMap = (EntityStatMap) ctx.getComponent(entity, EntityStatMap.getComponentType());
HytaleAssert.assertNotNull("Entity should have EntityStatMap", statMap);
int healthStat = DefaultEntityStatTypes.getHealth();
statMap.subtractStatValue(healthStat, 10.0f);
ctx.flush();
ctx.waitTicks(1);
CombatAssert.assertHealthBelow(store, entity, statMap.get(healthStat).getMax());
StatsAssert.assertAlive(store, entity);
}
@CombatTest
@Order(3)
@DisplayName("Lethal damage kills the entity")
void lethalDamageCausesDeath(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Kweebec_Sapling", 20, 64, 20);
ctx.waitTicks(1);
var statMap = (EntityStatMap) ctx.getComponent(entity, EntityStatMap.getComponentType());
int healthStat = DefaultEntityStatTypes.getHealth();
statMap.subtractStatValue(healthStat, 9999.0f);
ctx.flush();
ctx.waitTicks(5);
Object store = ctx.getStore();
StatsAssert.assertDead(store, entity);
}
@CombatTest
@Order(4)
@DisplayName("Health can be checked at a specific value after partial damage")
void healthEqualsAfterPartialDamage(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Trork_Warrior", 0, 64, 0);
ctx.waitTicks(1);
Object store = ctx.getStore();
var statMap = (EntityStatMap) ctx.getComponent(entity, EntityStatMap.getComponentType());
int healthStat = DefaultEntityStatTypes.getHealth();
statMap.subtractStatValue(healthStat, 25.0f);
ctx.flush();
ctx.waitTicks(1);
StatsAssert.assertAlive(store, entity);
CombatAssert.assertAlive(store, entity);
}
@CombatTest
@Order(5)
@DisplayName("Stat modifier is applied and visible")
void statModifierIsApplied(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Kweebec_Sapling", 30, 64, 30);
ctx.waitTicks(1);
Object store = ctx.getStore();
// Apply a named defense modifier, simulating equipping armor.
// Modifiers alter a stat's computed value without changing the base.
ctx.applyStatModifier(entity, "DEFENSE", "iron_chestplate_defense", 15.0f);
ctx.waitTicks(1);
StatsAssert.assertHasModifier(store, entity, ctx.getStatType("DEFENSE"), "iron_chestplate_defense");
}
@CombatTest
@Order(6)
@DisplayName("Removing a stat modifier restores original stat")
void statModifierCanBeRemoved(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Kweebec_Sapling", 40, 64, 40);
ctx.waitTicks(1);
Object store = ctx.getStore();
// Apply then remove the modifier.
ctx.applyStatModifier(entity, "DEFENSE", "temporary_buff", 20.0f);
ctx.waitTicks(1);
StatsAssert.assertHasModifier(store, entity, ctx.getStatType("DEFENSE"), "temporary_buff");
ctx.removeStatModifier(entity, "DEFENSE", "temporary_buff");
ctx.waitTicks(1);
StatsAssert.assertNoModifier(store, entity, ctx.getStatType("DEFENSE"), "temporary_buff");
}
@CombatTest
@Order(7)
@DisplayName("Knockback is applied on melee hit")
void meleeHitAppliesKnockback(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Trork_Warrior", 50, 64, 50);
ctx.waitTicks(1);
var statMap = (EntityStatMap) ctx.getComponent(entity, EntityStatMap.getComponentType());
int healthStat = DefaultEntityStatTypes.getHealth();
statMap.subtractStatValue(healthStat, 5.0f);
ctx.flush();
ctx.waitTicks(1);
Object store = ctx.getStore();
CombatAssert.assertHasKnockback(store, entity);
}
}