Skip to content

Commit a541d9b

Browse files
authored
Add TornadoAttackMode
Add TornadoAttackMode(Entity Burst)
1 parent 90ef0de commit a541d9b

17 files changed

Lines changed: 561 additions & 14 deletions

File tree

src/main/java/forj/elementcombating/impl/Elements.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
import forj.elementcombating.ElementCombating;
44
import forj.elementcombating.element.*;
5-
import forj.elementcombating.impl.attack_modes.PulseAttackMode;
6-
import forj.elementcombating.impl.attack_modes.ShieldBashAttackMode;
7-
import forj.elementcombating.impl.attack_modes.SpurtAttackMode;
8-
import forj.elementcombating.impl.attack_modes.SweepAttackMode;
5+
import forj.elementcombating.impl.attack_modes.*;
96
import forj.elementcombating.impl.entity.entity.ElementCrystalEntity;
107
import forj.elementcombating.impl.entity.entity.ElementDamageCrystalEntity;
8+
import forj.elementcombating.impl.entity.entity.TornadoEntity;
119
import forj.elementcombating.impl.status_effect.ElementEffects;
1210
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
1311
import net.minecraft.entity.LivingEntity;
@@ -139,6 +137,7 @@ public class Elements {
139137
public static final AttackMode SpurtMobMode = new SpurtAttackMode(AttributeType.ENTITY_SKILL);
140138
public static final AttackMode ShieldBashSkillMode = new ShieldBashAttackMode(AttributeType.ITEM_SKILL);
141139
public static final AttackMode ShieldBashMobMode = new ShieldBashAttackMode(AttributeType.ENTITY_SKILL);
140+
public static final AttackMode TornadoMode = new TornadoAttackMode(AttributeType.ENTITY_BURST);
142141

143142

144143
//Register
@@ -147,18 +146,19 @@ public static void init() {
147146
ElementRegistry.registerElementTypes(Fire, Water, Electricity, Plant, Sculk, Soul, Void, Stone, Wind);
148147
ElementRegistry.registerElementEffects(BurstEffect, GrowEffect, ActivateEffect);
149148

150-
Fire.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode);
151-
Water.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode);
152-
Electricity.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode);
149+
Fire.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, TornadoMode);
150+
Water.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, TornadoMode);
151+
Electricity.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, TornadoMode);
153152
Plant.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, ShieldBashSkillMode, ShieldBashMobMode);
154153
Sculk.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode);
155-
Soul.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, ShieldBashSkillMode, ShieldBashMobMode);
154+
Soul.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, ShieldBashSkillMode, ShieldBashMobMode, TornadoMode);
156155
Void.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode);
157156
Stone.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, ShieldBashSkillMode, ShieldBashMobMode);
158-
Wind.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode);
157+
Wind.addAvailableMode(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, TornadoMode);
159158

160-
ElementRegistry.registerAttackModes(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, ShieldBashSkillMode, ShieldBashMobMode);
159+
ElementRegistry.registerAttackModes(SweepSkillMode, SweepMobMode, PulseMode, SpurtSkillMode, SpurtMobMode, ShieldBashSkillMode, ShieldBashMobMode, TornadoMode);
161160

161+
TornadoEntity.init();
162162

163163
registerElementReaction(Fire, Water, Vaporize);
164164
registerElementReaction(Fire, Electricity, Overload);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package forj.elementcombating.impl.attack_modes;
2+
3+
import forj.elementcombating.element.AttributeType;
4+
import forj.elementcombating.element.AttributedAttackMode;
5+
import forj.elementcombating.element.ElementAttribute;
6+
import forj.elementcombating.element.StatAccessor;
7+
import forj.elementcombating.impl.entity.entity.TornadoEntity;
8+
import forj.elementcombating.utils.attribute_creator.AttributeCreator;
9+
import net.minecraft.entity.LivingEntity;
10+
11+
import java.util.Map;
12+
13+
public class TornadoAttackMode extends AttributedAttackMode {
14+
public TornadoAttackMode(AttributeType attributeType) {
15+
super(attributeType, "tornado");
16+
}
17+
18+
@Override
19+
public void onUse(LivingEntity user, ElementAttribute attribute, Map<String, AttributeCreator.Num> attributes) {
20+
int lastTicks = attributes.get("lastTicks").getIntValue();
21+
int duration = attributes.get("duration").getIntValue();
22+
float damage = attributes.get("damage").getFloatValue();
23+
int damageInterval = attributes.get("damageInterval").getIntValue();
24+
float range = attributes.get("range").getFloatValue();
25+
double speed = attributes.get("speed").getDoubleValue();
26+
int cooldown = attributes.get("cooldown").getIntValue();
27+
((StatAccessor)user).getCoolDownManager()
28+
.set(attribute.getAttributeType(), attribute.getElementType(), cooldown);
29+
TornadoEntity tornado = new TornadoEntity(user.getWorld(), user, lastTicks, damageInterval,
30+
duration, attribute.getLevel(), damage, range);
31+
double yawRadians = Math.toRadians(-user.getYaw());
32+
double velocityX = speed * Math.sin(yawRadians);
33+
double velocityZ = speed * Math.cos(yawRadians);
34+
tornado.setVelocity(velocityX, 0, velocityZ);
35+
tornado.setPos(user.getX(), user.getY(), user.getZ());
36+
user.getWorld().spawnEntity(tornado);
37+
tornado.setElementType(attribute.getElementType());
38+
}
39+
}

src/main/java/forj/elementcombating/impl/entity/Entities.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import forj.elementcombating.impl.entity.entity.ElementCrystalEntity;
44
import forj.elementcombating.impl.entity.entity.ElementDamageCrystalEntity;
5+
import forj.elementcombating.impl.entity.entity.TornadoEntity;
56
import forj.elementcombating.impl.entity.model.ElementDamageCrystalEntityModel;
67
import forj.elementcombating.impl.entity.model.ElementCrystalEntityModel;
8+
import forj.elementcombating.impl.entity.model.TornadoEntityModel;
79
import forj.elementcombating.impl.entity.renderer.GeoEntityRenderer;
810
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
911
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
@@ -18,12 +20,15 @@ public class Entities {
1820
FabricEntityTypeBuilder.create(SpawnGroup.MISC, (EntityType.EntityFactory<ElementCrystalEntity>) ElementCrystalEntity::new).dimensions(EntityDimensions.fixed(0.375f, 0.8125f)).build());
1921
public static final EntityType<ElementDamageCrystalEntity> ELEMENT_DAMAGE_CRYSTAL_ENTITY = Registry.register(Registry.ENTITY_TYPE, new Identifier("element_combating", "recorder"),
2022
FabricEntityTypeBuilder.create(SpawnGroup.MISC, (EntityType.EntityFactory<ElementDamageCrystalEntity>) ElementDamageCrystalEntity::new).dimensions(EntityDimensions.fixed(0.375f, 0.8125f)).build());
23+
public static final EntityType<TornadoEntity> TORNADO_ENTITY = Registry.register(Registry.ENTITY_TYPE, new Identifier("element_combating", "tornado"),
24+
FabricEntityTypeBuilder.create(SpawnGroup.MISC, (EntityType.EntityFactory<TornadoEntity>) TornadoEntity::new).dimensions(EntityDimensions.fixed(1.5f, 2.8f)).build());
2125

2226
public static void init() {
2327
}
2428

2529
public static void initClient() {
2630
EntityRendererRegistry.register(ELEMENT_CRYSTAL_ENTITY, GeoEntityRenderer.getRendererFactory(new ElementCrystalEntityModel()));
2731
EntityRendererRegistry.register(ELEMENT_DAMAGE_CRYSTAL_ENTITY, GeoEntityRenderer.getRendererFactory(new ElementDamageCrystalEntityModel()));
32+
EntityRendererRegistry.register(TORNADO_ENTITY, GeoEntityRenderer.getRendererFactory(new TornadoEntityModel()));
2833
}
2934
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package forj.elementcombating.impl.entity.entity;
2+
3+
import forj.elementcombating.DatapackProcessor;
4+
import forj.elementcombating.element.ElementRegistry;
5+
import forj.elementcombating.element.ElementType;
6+
import forj.elementcombating.impl.Elements;
7+
import forj.elementcombating.impl.Utils;
8+
import forj.elementcombating.impl.entity.Entities;
9+
import forj.elementcombating.utils.attribute_creator.AttributeCreator;
10+
import forj.elementcombating.utils.attribute_creator.AttributeCreatorProvider;
11+
import net.minecraft.entity.Entity;
12+
import net.minecraft.entity.EntityType;
13+
import net.minecraft.entity.LivingEntity;
14+
import net.minecraft.entity.MovementType;
15+
import net.minecraft.entity.attribute.EntityAttributes;
16+
import net.minecraft.entity.data.DataTracker;
17+
import net.minecraft.entity.data.TrackedData;
18+
import net.minecraft.nbt.NbtCompound;
19+
import net.minecraft.network.Packet;
20+
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket;
21+
import net.minecraft.server.world.ServerWorld;
22+
import net.minecraft.util.Util;
23+
import net.minecraft.util.math.Vec3d;
24+
import net.minecraft.world.World;
25+
import software.bernie.geckolib3.core.IAnimatable;
26+
import software.bernie.geckolib3.core.PlayState;
27+
import software.bernie.geckolib3.core.builder.AnimationBuilder;
28+
import software.bernie.geckolib3.core.controller.AnimationController;
29+
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
30+
import software.bernie.geckolib3.core.manager.AnimationData;
31+
import software.bernie.geckolib3.core.manager.AnimationFactory;
32+
33+
import java.util.HashMap;
34+
import java.util.List;
35+
import java.util.Optional;
36+
import java.util.UUID;
37+
38+
public class TornadoEntity extends Entity implements IAnimatable {
39+
private static final TrackedData<Optional<ElementType>> ELEMENT_TYPE = DataTracker.registerData(TornadoEntity.class, Utils.OptionalElementTypeTrackedDataHandler);
40+
private static AttributeCreator velocityProvider;
41+
42+
public static void reloadVelocityProvider() {
43+
velocityProvider = AttributeCreatorProvider.Instance.getCreator("tornado_mode_attract_velocity");
44+
}
45+
46+
public static void init() {
47+
DatapackProcessor.registerOnReload(TornadoEntity::reloadVelocityProvider);
48+
}
49+
50+
private final AnimationFactory factory = new AnimationFactory(this);
51+
52+
53+
private int damageInterval, lastTicks, duration, level, damageCooldown = 0;
54+
private float damage, attractRange;
55+
private LivingEntity owner;
56+
57+
58+
public TornadoEntity(EntityType<?> type, World world) {
59+
super(type, world);
60+
}
61+
62+
public TornadoEntity(World world, LivingEntity owner, int lastTicks, int damageInterval, int duration, int level, float damage, float attractRange) {
63+
super(Entities.TORNADO_ENTITY, world);
64+
this.owner = owner;
65+
this.lastTicks = lastTicks;
66+
this.attractRange = attractRange;
67+
this.damageInterval = damageInterval;
68+
this.duration = duration;
69+
this.level = level;
70+
this.damage = damage;
71+
}
72+
73+
public ElementType getElementType() {
74+
return this.dataTracker.get(ELEMENT_TYPE).orElse(Elements.Wind);
75+
}
76+
77+
public LivingEntity getOwner() {
78+
return this.owner;
79+
}
80+
81+
public void setElementType(ElementType elementType) {
82+
this.dataTracker.set(ELEMENT_TYPE, Optional.of(elementType));
83+
}
84+
85+
private void attract(LivingEntity target, double strength) {
86+
strength *= 1.0 - target.getAttributeValue(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE);
87+
if (strength <= 0.0) return;
88+
Vec3d direction = this.getPos().subtract(target.getPos()).normalize();
89+
target.setVelocity(target.getVelocity().add(direction.multiply(strength)));
90+
target.velocityModified = true;
91+
target.velocityDirty = true;
92+
}
93+
94+
@Override
95+
public void tick() {
96+
super.tick();
97+
Vec3d velocity = this.getVelocity();
98+
this.setVelocity(new Vec3d(velocity.x, 0, velocity.z));
99+
this.move(MovementType.SELF, this.getVelocity());
100+
if (this.world.isClient || this.getWorld().isClient()) return;
101+
if (getElementType() == null) {
102+
setElementType(Elements.Wind);
103+
}
104+
if (getOwner() == null || --this.lastTicks < 0) {
105+
this.discard();
106+
return;
107+
}
108+
//attract entities
109+
List<LivingEntity> entities = this.world.getEntitiesByClass(LivingEntity.class, this.getBoundingBox().expand(this.attractRange), e -> true);
110+
for (LivingEntity entity : entities) {
111+
if (entity == getOwner()) continue;
112+
double strength = velocityProvider.create(
113+
Util.make(new HashMap<>(), map -> {
114+
map.put("distance", new AttributeCreator.Num(entity.getPos().distanceTo(this.getPos())));
115+
map.put("attractRange", new AttributeCreator.Num(this.attractRange));
116+
})
117+
).get("strength").getDoubleValue();
118+
attract(entity, strength);
119+
}
120+
if (--damageCooldown > 0) return;
121+
damageCooldown = damageInterval;
122+
List<LivingEntity> targets = this.world.getEntitiesByClass(LivingEntity.class, this.getBoundingBox(), e -> true);
123+
for (LivingEntity target : targets) {
124+
if (target == this.owner) continue;
125+
getElementType().attack(target, this.owner, this.level, this.duration, this.damage);
126+
}
127+
}
128+
129+
@Override
130+
protected void initDataTracker() {
131+
this.dataTracker.startTracking(ELEMENT_TYPE, Optional.empty());
132+
}
133+
134+
@Override
135+
protected void readCustomDataFromNbt(NbtCompound nbt) {
136+
try {
137+
String id = nbt.getString("element_type");
138+
UUID uuid = nbt.getUuid("owner");
139+
this.lastTicks = nbt.getInt("lastTicks");
140+
Entity entity = ((ServerWorld) this.world).getEntity(uuid);
141+
this.damage = nbt.getFloat("damage");
142+
this.duration = nbt.getInt("duration");
143+
this.level = nbt.getInt("level");
144+
this.damageInterval = nbt.getInt("damageInterval");
145+
this.attractRange = nbt.getFloat("attractRange");
146+
if (entity instanceof LivingEntity) this.owner = (LivingEntity) entity;
147+
try {
148+
this.dataTracker.set(ELEMENT_TYPE, Optional.of(ElementRegistry.getElementTypes().get(id)));
149+
} catch (IllegalArgumentException e) {
150+
this.dataTracker.set(ELEMENT_TYPE, Optional.empty());
151+
}
152+
} catch (NullPointerException e) {
153+
if (this.world.isClient) return;
154+
this.discard();
155+
}
156+
}
157+
158+
@Override
159+
protected void writeCustomDataToNbt(NbtCompound nbt) {
160+
if (this.world.isClient) return;
161+
if (getOwner() == null) {
162+
this.discard();
163+
return;
164+
}
165+
nbt.putString("element_type", getElementType().getId());
166+
nbt.putUuid("owner", this.owner.getUuid());
167+
nbt.putInt("lastTicks", this.lastTicks);
168+
nbt.putFloat("damage", this.damage);
169+
nbt.putInt("duration", this.duration);
170+
nbt.putInt("level", this.level);
171+
nbt.putInt("damageInterval", this.damageInterval);
172+
nbt.putFloat("attractRange", this.attractRange);
173+
}
174+
175+
176+
@Override
177+
public Packet<?> createSpawnPacket() {
178+
return new EntitySpawnS2CPacket(this);
179+
}
180+
181+
@Override
182+
public void registerControllers(AnimationData data) {
183+
data.addAnimationController(new AnimationController<>(this, "controller", 0, this::predicate));
184+
}
185+
186+
private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
187+
event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.tornado.loop", true));
188+
return PlayState.CONTINUE;
189+
}
190+
191+
@Override
192+
public AnimationFactory getFactory() {
193+
return factory;
194+
}
195+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package forj.elementcombating.impl.entity.model;
2+
3+
import forj.elementcombating.impl.entity.entity.TornadoEntity;
4+
import net.minecraft.util.Identifier;
5+
import software.bernie.geckolib3.model.AnimatedGeoModel;
6+
7+
public class TornadoEntityModel extends AnimatedGeoModel<TornadoEntity> {
8+
@Override
9+
public Identifier getModelLocation(TornadoEntity object) {
10+
return new Identifier("element_combating", "geo/tornado.geo.json");
11+
}
12+
13+
@Override
14+
public Identifier getTextureLocation(TornadoEntity object) {
15+
return new Identifier("element_combating", "textures/entity/tornado_" + object.getElementType() + ".png");
16+
}
17+
18+
@Override
19+
public Identifier getAnimationFileLocation(TornadoEntity animatable) {
20+
return new Identifier("element_combating", "animations/tornado.animation.json");
21+
}
22+
}

0 commit comments

Comments
 (0)