Runic enderman beam attack

This commit is contained in:
Sarinsa 2022-08-27 03:05:29 +02:00 committed by Sarinsa
parent 06a8962b27
commit 682cd82672
9 changed files with 334 additions and 40 deletions

View file

@ -10,6 +10,7 @@ import fathertoast.specialmobs.common.config.Config;
import fathertoast.specialmobs.common.core.SpecialMobs; import fathertoast.specialmobs.common.core.SpecialMobs;
import fathertoast.specialmobs.common.core.register.SMEntities; import fathertoast.specialmobs.common.core.register.SMEntities;
import fathertoast.specialmobs.common.entity.creeper.EnderCreeperEntity; import fathertoast.specialmobs.common.entity.creeper.EnderCreeperEntity;
import fathertoast.specialmobs.common.entity.enderman.RunicEndermanEntity;
import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity; import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity;
import fathertoast.specialmobs.common.entity.silverfish.PufferSilverfishEntity; import fathertoast.specialmobs.common.entity.silverfish.PufferSilverfishEntity;
import fathertoast.specialmobs.common.entity.skeleton.NinjaSkeletonEntity; import fathertoast.specialmobs.common.entity.skeleton.NinjaSkeletonEntity;
@ -83,10 +84,12 @@ public class ClientRegister {
registerSpeciesRenderer( CorporealShiftGhastEntity.SPECIES, CorporealShiftGhastRenderer::new ); registerSpeciesRenderer( CorporealShiftGhastEntity.SPECIES, CorporealShiftGhastRenderer::new );
registerSpeciesRenderer( RunicEndermanEntity.SPECIES, RunicEndermanRenderer::new );
// Other // Other
registerRenderer( SMEntities.BONE_SHRAPNEL, BoneShrapnelRenderer::new ); registerRenderer( SMEntities.BONE_SHRAPNEL, BoneShrapnelRenderer::new );
registerRenderer( SMEntities.BUG_SPIT, BugSpitRenderer::new ); registerRenderer( SMEntities.BUG_SPIT, BugSpitRenderer::new );
registerSpriteRenderer( SMEntities.CORPOREAL_FIREBALL, game, 3.0F, true ); registerSpriteRenderer( SMEntities.INCORPOREAL_FIREBALL, game, 3.0F, true );
registerRenderer( SMEntities.FISHING_BOBBER, SpecialFishingBobberRenderer::new ); registerRenderer( SMEntities.FISHING_BOBBER, SpecialFishingBobberRenderer::new );
} }

View file

@ -0,0 +1,118 @@
package fathertoast.specialmobs.client.renderer.entity.species;
import fathertoast.specialmobs.common.entity.enderman.RunicEndermanEntity;
import net.minecraft.client.renderer.entity.model.BipedModel;
import net.minecraft.client.renderer.model.ModelRenderer;
/** Epic copy-paste of {@link net.minecraft.client.renderer.entity.model.EndermanModel} */
public class RunicEndermanModel<T extends RunicEndermanEntity> extends BipedModel<T> {
public boolean carrying;
public boolean creepy;
public RunicEndermanModel(float something) {
super(0.0F, -14.0F, 64, 32);
float f = -14.0F;
this.hat = new ModelRenderer(this, 0, 16);
this.hat.addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, something - 0.5F);
this.hat.setPos(0.0F, -14.0F, 0.0F);
this.body = new ModelRenderer(this, 32, 16);
this.body.addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, something);
this.body.setPos(0.0F, -14.0F, 0.0F);
this.rightArm = new ModelRenderer(this, 56, 0);
this.rightArm.addBox(-1.0F, -2.0F, -1.0F, 2.0F, 30.0F, 2.0F, something);
this.rightArm.setPos(-3.0F, -12.0F, 0.0F);
this.leftArm = new ModelRenderer(this, 56, 0);
this.leftArm.mirror = true;
this.leftArm.addBox(-1.0F, -2.0F, -1.0F, 2.0F, 30.0F, 2.0F, something);
this.leftArm.setPos(5.0F, -12.0F, 0.0F);
this.rightLeg = new ModelRenderer(this, 56, 0);
this.rightLeg.addBox(-1.0F, 0.0F, -1.0F, 2.0F, 30.0F, 2.0F, something);
this.rightLeg.setPos(-2.0F, -2.0F, 0.0F);
this.leftLeg = new ModelRenderer(this, 56, 0);
this.leftLeg.mirror = true;
this.leftLeg.addBox(-1.0F, 0.0F, -1.0F, 2.0F, 30.0F, 2.0F, something);
this.leftLeg.setPos(2.0F, -2.0F, 0.0F);
}
@Override
public void setupAnim(T enderman, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
super.setupAnim(enderman, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
this.head.visible = true;
this.body.xRot = 0.0F;
this.body.y = -14.0F;
this.body.z = -0.0F;
this.rightLeg.xRot -= 0.0F;
this.leftLeg.xRot -= 0.0F;
this.rightArm.xRot = (float)((double)this.rightArm.xRot * 0.5D);
this.leftArm.xRot = (float)((double)this.leftArm.xRot * 0.5D);
this.rightLeg.xRot = (float)((double)this.rightLeg.xRot * 0.5D);
this.leftLeg.xRot = (float)((double)this.leftLeg.xRot * 0.5D);
if (this.rightArm.xRot > 0.4F) {
this.rightArm.xRot = 0.4F;
}
if (this.leftArm.xRot > 0.4F) {
this.leftArm.xRot = 0.4F;
}
if (this.rightArm.xRot < -0.4F) {
this.rightArm.xRot = -0.4F;
}
if (this.leftArm.xRot < -0.4F) {
this.leftArm.xRot = -0.4F;
}
if (this.rightLeg.xRot > 0.4F) {
this.rightLeg.xRot = 0.4F;
}
if (this.leftLeg.xRot > 0.4F) {
this.leftLeg.xRot = 0.4F;
}
if (this.rightLeg.xRot < -0.4F) {
this.rightLeg.xRot = -0.4F;
}
if (this.leftLeg.xRot < -0.4F) {
this.leftLeg.xRot = -0.4F;
}
if (this.carrying) {
this.rightArm.xRot = -0.5F;
this.leftArm.xRot = -0.5F;
this.rightArm.zRot = 0.05F;
this.leftArm.zRot = -0.05F;
}
this.rightArm.z = 0.0F;
this.leftArm.z = 0.0F;
this.rightLeg.z = 0.0F;
this.leftLeg.z = 0.0F;
this.rightLeg.y = -5.0F;
this.leftLeg.y = -5.0F;
this.head.z = -0.0F;
this.head.y = -13.0F;
this.hat.x = this.head.x;
this.hat.y = this.head.y;
this.hat.z = this.head.z;
this.hat.xRot = this.head.xRot;
this.hat.yRot = this.head.yRot;
this.hat.zRot = this.head.zRot;
if (this.creepy) {
this.head.y -= 5.0F;
}
this.rightArm.setPos(-5.0F, -12.0F, 0.0F);
this.leftArm.setPos(5.0F, -12.0F, 0.0F);
if (enderman.getBeamTargetId().isPresent()) {
leftArm.xRot = -0.5F;
rightArm.xRot = -0.5F;
leftArm.zRot = -0.25F;
rightArm.zRot = 0.25F;
}
}
}

View file

@ -0,0 +1,108 @@
package fathertoast.specialmobs.client.renderer.entity.species;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
import fathertoast.specialmobs.common.entity.ISpecialMob;
import fathertoast.specialmobs.common.entity.enderman.RunicEndermanEntity;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EnderDragonRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix3f;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3f;
public class RunicEndermanRenderer extends MobRenderer<RunicEndermanEntity, RunicEndermanModel<RunicEndermanEntity>> {
public static final ResourceLocation CRYSTAL_BEAM_LOCATION = new ResourceLocation("textures/entity/end_crystal/end_crystal_beam.png");
private static final RenderType BEAM = RenderType.entitySmoothCutout(CRYSTAL_BEAM_LOCATION);
private final float baseShadowRadius;
public RunicEndermanRenderer(EntityRendererManager rendererManager) {
super(rendererManager, new RunicEndermanModel<>(0.0F), 0.5F);
baseShadowRadius = shadowRadius;
addLayer( new SpecialMobEyesLayer<>( this ) );
addLayer( new SpecialMobOverlayLayer<>( this, new RunicEndermanModel<>( 0.25F ) ) );
}
@Override
public void render(RunicEndermanEntity enderman, float rotation, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) {
if (enderman.getBeamTargetId().isPresent()) {
Entity entity = enderman.level.getEntity(enderman.getBeamTargetId().getAsInt());
if (entity != null) {
matrixStack.pushPose();
float x = (float)(entity.getX() - MathHelper.lerp(partialTicks, enderman.xo, enderman.getX()));
float y = (float)(entity.getY() - MathHelper.lerp(partialTicks, enderman.yo, enderman.getY()));
float z = (float)(entity.getZ() - MathHelper.lerp(partialTicks, enderman.zo, enderman.getZ()));
renderBeamAttack(x, y, z, partialTicks, enderman.tickCount, matrixStack, buffer, packedLight);
matrixStack.popPose();
}
}
super.render(enderman, rotation, partialTicks, matrixStack, buffer, packedLight);
}
@Override
public ResourceLocation getTextureLocation(RunicEndermanEntity enderman) {
return ((ISpecialMob<?>) enderman).getSpecialData().getTexture();
}
@Override
protected void scale(RunicEndermanEntity entity, MatrixStack matrixStack, float partialTick ) {
super.scale( entity, matrixStack, partialTick );
final float scale = ((ISpecialMob<?>) entity).getSpecialData().getRenderScale();
shadowRadius = baseShadowRadius * scale;
matrixStack.scale( scale, scale, scale );
}
/** Copy-paste Ender Crystal render code. {@link EnderDragonRenderer#renderCrystalBeams(float, float, float, float, int, MatrixStack, IRenderTypeBuffer, int)} */
private void renderBeamAttack(float x, float y, float z, float partialTicks, int tickCount, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) {
float f = MathHelper.sqrt(x * x + z * z);
float xyzMul = x * x + y * y + z * z;
float f1 = MathHelper.sqrt(xyzMul);
matrixStack.pushPose();
matrixStack.translate(0.0D, 2.0D, 0.0D);
matrixStack.mulPose(Vector3f.YP.rotation((float)(-Math.atan2(z, x)) - ((float)Math.PI / 2F)));
matrixStack.mulPose(Vector3f.XP.rotation((float)(-Math.atan2(f, y)) - ((float)Math.PI / 2F)));
IVertexBuilder ivertexbuilder = buffer.getBuffer(BEAM);
float f2 = 0.0F - ((float)tickCount + partialTicks) * 0.01F;
float f3 = MathHelper.sqrt(xyzMul) / 32.0F - ((float)tickCount + partialTicks) * 0.01F;
float f4 = 0.0F;
float f5 = 0.75F;
float f6 = 0.0F;
MatrixStack.Entry entry = matrixStack.last();
Matrix4f matrix4f = entry.pose();
Matrix3f matrix3f = entry.normal();
for(int j = 1; j <= 8; ++j) {
float f7 = MathHelper.sin((float)j * ((float)Math.PI * 2F) / 8.0F) * 0.75F;
float f8 = MathHelper.cos((float)j * ((float)Math.PI * 2F) / 8.0F) * 0.75F;
float f9 = (float)j / 8.0F;
ivertexbuilder.vertex(matrix4f, f4 * 0.2F, f5 * 0.2F, 0.0F).color(0, 0, 0, 255).uv(f6, f2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(packedLight).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
ivertexbuilder.vertex(matrix4f, f4, f5, f1).color(255, 100, 255, 255).uv(f6, f3).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(packedLight).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
ivertexbuilder.vertex(matrix4f, f7, f8, f1).color(255, 100, 255, 255).uv(f9, f3).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(packedLight).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
ivertexbuilder.vertex(matrix4f, f7 * 0.2F, f8 * 0.2F, 0.0F).color(0, 0, 0, 255).uv(f9, f2).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(packedLight).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
f4 = f7;
f5 = f8;
f6 = f9;
}
matrixStack.popPose();
}
}

View file

@ -29,7 +29,7 @@ public class SMEntities {
EntityType.Builder.<BugSpitEntity>of( BugSpitEntity::new, EntityClassification.MISC ) EntityType.Builder.<BugSpitEntity>of( BugSpitEntity::new, EntityClassification.MISC )
.sized( 0.25F, 0.25F ).clientTrackingRange( 4 ).updateInterval( 10 ) ); .sized( 0.25F, 0.25F ).clientTrackingRange( 4 ).updateInterval( 10 ) );
public static final RegistryObject<EntityType<IncorporealFireballEntity>> CORPOREAL_FIREBALL = register( "incorporeal_fireball", public static final RegistryObject<EntityType<IncorporealFireballEntity>> INCORPOREAL_FIREBALL = register( "incorporeal_fireball",
EntityType.Builder.<IncorporealFireballEntity>of( IncorporealFireballEntity::new, EntityClassification.MISC ) EntityType.Builder.<IncorporealFireballEntity>of( IncorporealFireballEntity::new, EntityClassification.MISC )
.sized( 1.0F, 1.0F ).clientTrackingRange( 4 ).updateInterval( 3 ) ); .sized( 1.0F, 1.0F ).clientTrackingRange( 4 ).updateInterval( 3 ) );

View file

@ -1,22 +0,0 @@
package fathertoast.specialmobs.common.entity.ai;
import fathertoast.specialmobs.common.entity.enderman.RunicEndermanEntity;
import net.minecraft.entity.ai.goal.Goal;
public class RunicAttackGoal extends Goal {
private final RunicEndermanEntity runicEnderman;
private final int attackTime;
private final float baseDamage;
public RunicAttackGoal( RunicEndermanEntity runicEnderman, int attackTime, float baseDamage ) {
this.runicEnderman = runicEnderman;
this.attackTime = attackTime;
this.baseDamage = baseDamage;
}
@Override
public boolean canUse() {
return false;
}
}

View file

@ -0,0 +1,68 @@
package fathertoast.specialmobs.common.entity.ai.goal;
import fathertoast.specialmobs.common.entity.enderman.RunicEndermanEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.MathHelper;
public class RunicEndermanBeamAttackGoal extends Goal {
private final RunicEndermanEntity runicEnderman;
private final int maxAttackTime;
private final double baseDamage;
private int attackTime;
public RunicEndermanBeamAttackGoal(RunicEndermanEntity runicEnderman, int maxAttackTime, double baseDamage ) {
this.runicEnderman = runicEnderman;
this.maxAttackTime = maxAttackTime;
this.baseDamage = baseDamage;
}
@Override
public boolean canUse() {
if (runicEnderman.isVehicle())
return false;
LivingEntity target = runicEnderman.getTarget();
return target != null
&& target.isAlive()
&& runicEnderman.getSensing().canSee(target)
&& (runicEnderman.tickCount % 8 == 0 && runicEnderman.getRandom().nextInt(10) == 0);
}
@Override
public boolean canContinueToUse() {
LivingEntity target = runicEnderman.getTarget();
return attackTime > 0 && target != null && target.isAlive() && runicEnderman.getSensing().canSee(target);
}
@Override
public void start() {
runicEnderman.setBeamTargetId(runicEnderman.getTarget().getId());
attackTime = maxAttackTime;
}
@Override
public void stop() {
runicEnderman.clearBeamTargetId();
attackTime = 0;
}
@SuppressWarnings("ConstantConditions")
@Override
public void tick() {
--attackTime;
if (attackTime <= 0) {
LivingEntity target = runicEnderman.getTarget();
double xRatio = MathHelper.sin(runicEnderman.yRot * ((float)Math.PI / 180F));
double zRatio = -MathHelper.cos(runicEnderman.yRot * ((float)Math.PI / 180F));
target.knockback(5, xRatio, zRatio);
target.hurt(DamageSource.mobAttack(runicEnderman), (float) baseDamage);
}
}
}

View file

@ -4,6 +4,7 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily; import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob; import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.MobHelper; import fathertoast.specialmobs.common.entity.MobHelper;
import fathertoast.specialmobs.common.entity.ai.goal.RunicEndermanBeamAttackGoal;
import fathertoast.specialmobs.common.util.References; import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder; import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
@ -11,9 +12,14 @@ import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.Attributes; import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.potion.Effects; import net.minecraft.potion.Effects;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.OptionalInt;
@SpecialMob @SpecialMob
public class RunicEndermanEntity extends _SpecialEndermanEntity { public class RunicEndermanEntity extends _SpecialEndermanEntity {
@ -57,8 +63,30 @@ public class RunicEndermanEntity extends _SpecialEndermanEntity {
//--------------- Variant-Specific Implementations ---------------- //--------------- Variant-Specific Implementations ----------------
public static final DataParameter<Boolean> BEAMING = EntityDataManager.defineId(RunicEndermanEntity.class, DataSerializers.BOOLEAN);
public static final DataParameter<OptionalInt> TARGET_ID = EntityDataManager.defineId(RunicEndermanEntity.class, DataSerializers.OPTIONAL_UNSIGNED_INT);
public RunicEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); } public RunicEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); }
@Override
protected void defineSynchedData() {
super.defineSynchedData();
entityData.define( BEAMING, false );
entityData.define( TARGET_ID, OptionalInt.empty() );
}
public OptionalInt getBeamTargetId() {
return entityData.get( TARGET_ID );
}
public void setBeamTargetId(int targetId) {
entityData.set( TARGET_ID, OptionalInt.of(targetId) );
}
public void clearBeamTargetId() {
entityData.set( TARGET_ID, OptionalInt.empty() );
}
/** Override to apply effects when this entity hits a target with a melee attack. */ /** Override to apply effects when this entity hits a target with a melee attack. */
@Override @Override
protected void onVariantAttack( LivingEntity target ) { protected void onVariantAttack( LivingEntity target ) {
@ -70,7 +98,6 @@ public class RunicEndermanEntity extends _SpecialEndermanEntity {
@Override @Override
protected void registerVariantGoals() { protected void registerVariantGoals() {
super.registerVariantGoals(); super.registerVariantGoals();
goalSelector.addGoal( 2, new RunicEndermanBeamAttackGoal(this, 50, 2.0D));
} }
// NOTE would be fun to try and make this mob shoot an 'end crystal laser' to deal ranged damage and/or knockback
} }

View file

@ -1,10 +1,8 @@
package fathertoast.specialmobs.common.entity.projectile; package fathertoast.specialmobs.common.entity.projectile;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.core.register.SMEntities; import fathertoast.specialmobs.common.core.register.SMEntities;
import fathertoast.specialmobs.common.core.register.SMItems; import fathertoast.specialmobs.common.core.register.SMItems;
import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity; import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity;
import fathertoast.specialmobs.common.util.References;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -42,21 +40,15 @@ public class IncorporealFireballEntity extends AbstractFireballEntity {
} }
public IncorporealFireballEntity(World world, CorporealShiftGhastEntity ghast, double x, double y, double z ) { public IncorporealFireballEntity(World world, CorporealShiftGhastEntity ghast, double x, double y, double z ) {
super( SMEntities.CORPOREAL_FIREBALL.get(), ghast, x, y, z, world ); super( SMEntities.INCORPOREAL_FIREBALL.get(), ghast, x, y, z, world );
target = ghast.getTarget(); target = ghast.getTarget();
} }
public IncorporealFireballEntity(World world, @Nullable PlayerEntity owner, LivingEntity target, double x, double y, double z ) { public IncorporealFireballEntity(World world, @Nullable PlayerEntity owner, LivingEntity target, double x, double y, double z ) {
super( SMEntities.CORPOREAL_FIREBALL.get(), owner, x, y, z, world ); super( SMEntities.INCORPOREAL_FIREBALL.get(), owner, x, y, z, world );
this.target = target; this.target = target;
} }
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Incorporeal Fireball",
"", "", "", "", "", "" );//TODO
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();

View file

@ -66,7 +66,7 @@ public class SMLanguageProvider extends LanguageProvider {
"", "", "", "", "", "" ) ); //TODO "", "", "", "", "", "" ) ); //TODO
translationList.add( References.translations( SMEntities.BUG_SPIT.get().getDescriptionId(), "Bug Spit", translationList.add( References.translations( SMEntities.BUG_SPIT.get().getDescriptionId(), "Bug Spit",
"", "", "", "", "", "" ) ); //TODO "", "", "", "", "", "" ) ); //TODO
translationList.add( References.translations( SMEntities.CORPOREAL_FIREBALL.get().getDescriptionId(), "Bug Spit", translationList.add( References.translations( SMEntities.INCORPOREAL_FIREBALL.get().getDescriptionId(), "Incorporeal Fireball",
"", "", "", "", "", "" ) ); //TODO "", "", "", "", "", "" ) ); //TODO
translationList.add( References.translations( SMEntities.FISHING_BOBBER.get().getDescriptionId(), "Fishing Bobber", translationList.add( References.translations( SMEntities.FISHING_BOBBER.get().getDescriptionId(), "Fishing Bobber",
"", "", "", "", "", "" ) ); //TODO "", "", "", "", "", "" ) ); //TODO