Jump to content

[1.12.2] How to get multiple Hitboxes for one Entity


_Cruelar_

Recommended Posts

Hi guys, I'm working on a Entity, Stone Talus from The Legend of Zelda: Breath of the Wild, which don't take any damage of getting hit except at an ore deposit located on his back. I thought about a second hitbox as a weak spot located at the deposit, but I've no Code yet for the weak spot, because I don't know how to start, but I'll look if I find a way to start, so maybe I can give the code soon.

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

Link to comment
Share on other sites

As far as I know minecraft only supports one hitbox per entity and there is no way to lift this limitation. If you want multiple hitboxes you need to use multiple entities(some kind of a "parent" entity that handles all the logic and "child" entities that handle the damage). I believe vanilla already does something similar with the enderdragon so that might be a good place to start.

Link to comment
Share on other sites

Thanks but how  it binds the MUltiParts to the ModelParts

My Code (AI is only for testing I'm working on a better one):

package com.cruelar.cruelars_triforcemod.entities.boss;

import com.cruelar.cruelars_triforcemod.Cruelars_Triforcemod_Core;
import jline.internal.Nullable;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.BossInfo;
import net.minecraft.world.BossInfoServer;
import net.minecraft.world.World;

public class Stone_Talus extends EntityMob implements IEntityMultiPart {

    public static final ResourceLocation LOOT = new ResourceLocation(Cruelars_Triforcemod_Core.MODID,"entities/stone_talus.json");
    public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("cruelars_triforcemod:textures/entity/stone_talus.png");
    private final BossInfoServer bossInfo;
    public final MultiPartEntityPart[] talusParts;
    public final MultiPartEntityPart Mainbody = new MultiPartEntityPart(this,"mainbody",8,8);
    public final MultiPartEntityPart Oredeposit = new MultiPartEntityPart(this,"oredeposit",1,1);

    public Stone_Talus(World world){
        super(world);
            this.setSize(2.0F,3.5F );
            this.isNonBoss();
            this.setEntityBoundingBox(new AxisAlignedBB(this.getEntityBoundingBox().minX-2,this.getEntityBoundingBox().minY,this.getEntityBoundingBox().minZ,this.getEntityBoundingBox().maxX+2,this.getEntityBoundingBox().maxY+4,this.getEntityBoundingBox().maxZ));
            this.bossInfo = (BossInfoServer)(new BossInfoServer(this.getDisplayName(), BossInfo.Color.RED, BossInfo.Overlay.PROGRESS));
            this.isImmuneToFire = true;
            this.talusParts=new MultiPartEntityPart[]{this.Mainbody,this.Oredeposit};
        }

    public void readEntityFromNBT(NBTTagCompound p_readEntityFromNBT_1_) {
        super.readEntityFromNBT(p_readEntityFromNBT_1_);
        if (this.hasCustomName()) {
            this.bossInfo.setName(this.getDisplayName());
        }

    }



    protected void updateAITasks() {
            super.updateAITasks();
            this.bossInfo.setPercent(this.getHealth() / this.getMaxHealth());
    }

    public void addTrackingPlayer(EntityPlayerMP p_addTrackingPlayer_1_) {
                super.addTrackingPlayer(p_addTrackingPlayer_1_);
                this.bossInfo.addPlayer(p_addTrackingPlayer_1_);
    }

    public void removeTrackingPlayer(EntityPlayerMP p_removeTrackingPlayer_1_) {
        super.removeTrackingPlayer(p_removeTrackingPlayer_1_);
        this.bossInfo.removePlayer(p_removeTrackingPlayer_1_);
    }

    public void setCustomNameTag(String p_setCustomNameTag_1_) {
        super.setCustomNameTag(p_setCustomNameTag_1_);
        this.bossInfo.setName(this.getDisplayName());
    }

    @Override
    protected void entityInit(){
            super.entityInit();
        }

        @Override
        protected void  applyEntityAttributes(){
            super.applyEntityAttributes();
            this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(300.0D);
            this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.1D);
            this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(10.0D);
            this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(32.0D);
            this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(10.0D);
            this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(100.0D);
        }

        @Override
        protected void initEntityAI(){
            this.tasks.addTask(0,new EntityAISwimming(this));
            this.tasks.addTask(2,new EntityAIAttackMelee(this,1.0D,true));
            this.tasks.addTask(5,new EntityAIMoveTowardsRestriction(this,1.0D));
            this.tasks.addTask(7,new EntityAIWander(this,1.0D));
            this.tasks.addTask(8,new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
            this.tasks.addTask(8,new EntityAILookIdle(this));
            this.applyEntityAI();
        }

        private void applyEntityAI() {
            this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
            this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true, EntityPigZombie.class));
            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityPlayer.class, true));
            this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<>(this, EntityVillager.class, true));
            this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<>(this, EntityIronGolem.class, true));
        }

        @Override
        public boolean attackEntityAsMob(Entity entity){
            return super.attackEntityAsMob(entity);
        }

        @Override
        @Nullable
        protected ResourceLocation getLootTable(){
            return LOOT;
        }

        @Override
        protected boolean isValidLightLevel(){
            return true;
        }

        @Override
        protected boolean canDropLoot () {
            return true;
        }

    @Override
        public int getMaxSpawnedInChunk(){
            return 1;
        }

        @Override
        public boolean isNonBoss(){
            return  false;
        }

    @Override
    public World getWorld() {
        return this.world;
    }

    @Override
    public boolean attackEntityFromPart(MultiPartEntityPart entityPart, DamageSource source, float damage) {
        if (entityPart==Oredeposit){
            return true;
        }
        return false;
    }
}

 

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

Link to comment
Share on other sites

When you instantinate the multipart you specify the width and the height of it. Those are the dimensions of your bounding box.

Then somewhere(presumably in your entity's update method) you update the positions of your multiparts using Entity#setLocationAndAngles. That also updates the position of the bounding box of that entity. See how EntityDragon handles the multipart positions in it's onLivingUpdate method.

Link to comment
Share on other sites

Still doesn't work.I can't see the Hitbox when I press F3+B. What' is wrong?

package com.cruelar.cruelars_triforcemod.entities.boss;

import com.cruelar.cruelars_triforcemod.Cruelars_Triforcemod_Core;
import jline.internal.Nullable;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.BossInfo;
import net.minecraft.world.BossInfoServer;
import net.minecraft.world.World;

public class Stone_Talus extends EntityMob implements IEntityMultiPart {

    public static final ResourceLocation LOOT = new ResourceLocation(Cruelars_Triforcemod_Core.MODID, "entities/stone_talus.json");
    public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("cruelars_triforcemod:textures/entity/stone_talus.png");
    private final BossInfoServer bossInfo;
    public final MultiPartEntityPart[] talusParts;
    public final MultiPartEntityPart Mainbody = new MultiPartEntityPart(this, "mainbody", 5, 5);
    public final MultiPartEntityPart Oredeposit = new MultiPartEntityPart(this, "oredeposit", 1, 1);
    public float prevAnimTime;
    public float animTime;

    public Stone_Talus(World world) {
        super(world);
        this.setSize(2.0F, 3.5F);
        this.isNonBoss();
        this.setHealth(this.getMaxHealth());
        this.bossInfo = (BossInfoServer) (new BossInfoServer(this.getDisplayName(), BossInfo.Color.RED, BossInfo.Overlay.PROGRESS));
        this.isImmuneToFire = true;
        this.talusParts = new MultiPartEntityPart[]{this.Mainbody, this.Oredeposit};
    }

    public void readEntityFromNBT(NBTTagCompound p_readEntityFromNBT_1_) {
        super.readEntityFromNBT(p_readEntityFromNBT_1_);
        if (this.hasCustomName()) {
            this.bossInfo.setName(this.getDisplayName());
        }

    }


    protected void updateAITasks() {
        super.updateAITasks();

    }

    public void addTrackingPlayer(EntityPlayerMP p_addTrackingPlayer_1_) {
        super.addTrackingPlayer(p_addTrackingPlayer_1_);
        this.bossInfo.addPlayer(p_addTrackingPlayer_1_);
    }

    public void removeTrackingPlayer(EntityPlayerMP p_removeTrackingPlayer_1_) {
        super.removeTrackingPlayer(p_removeTrackingPlayer_1_);
        this.bossInfo.removePlayer(p_removeTrackingPlayer_1_);
    }

    public void setCustomNameTag(String p_setCustomNameTag_1_) {
        super.setCustomNameTag(p_setCustomNameTag_1_);
        this.bossInfo.setName(this.getDisplayName());
    }

    @Override
    protected void entityInit() {
        super.entityInit();
    }

    @Override
    protected void applyEntityAttributes() {
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(300.0D);
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.1D);
        this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(32.0D);
        this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(100.0D);
    }

    @Override
    protected void initEntityAI() {
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(2, new EntityAIAttackMelee(this, 1.0D, true));
        this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 1.0D));
        this.tasks.addTask(7, new EntityAIWander(this, 1.0D));
        this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(8, new EntityAILookIdle(this));
        this.applyEntityAI();
    }

    private void applyEntityAI() {
        this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
        this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true, EntityPigZombie.class));
        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityPlayer.class, true));
        this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<>(this, EntityVillager.class, true));
        this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<>(this, EntityIronGolem.class, true));
    }

    @Override
    public boolean attackEntityAsMob(Entity entity) {
        return super.attackEntityAsMob(entity);
    }

    @Override
    @Nullable
    protected ResourceLocation getLootTable() {
        return LOOT;
    }

    @Override
    protected boolean isValidLightLevel() {
        return true;
    }

    @Override
    protected boolean canDropLoot() {
        return true;
    }

    @Override
    public int getMaxSpawnedInChunk() {
        return 1;
    }

    @Override
    public boolean isNonBoss() {
        return false;
    }

    @Override
    public World getWorld() {
        return this.world;
    }

    @Override
    public boolean attackEntityFromPart(MultiPartEntityPart entityPart, DamageSource source, float damage) {
        return entityPart == Oredeposit;
    }

    @Override
    public void onLivingUpdate() {
        if (this.world.isRemote) {
            this.setHealth(this.getHealth());
        }
        this.prevAnimTime = this.animTime;
        if (this.getHealth() <= 0.0F) {
            float f12 = (this.rand.nextFloat() - 0.5F) * 8.0F;
            float f13 = (this.rand.nextFloat() - 0.5F) * 4.0F;
            float f15 = (this.rand.nextFloat() - 0.5F) * 8.0F;
            this.world.spawnParticle(EnumParticleTypes.SPELL_MOB_AMBIENT, this.posX + (double) f12, this.posY + 2.0D + (double) f13, this.posZ + (double) f15, 0.0D, 0.0D, 0.0D);
        }
        if (this.isAIDisabled()) {
            this.animTime = 0.5F;
        } else {
            Mainbody.onUpdate();
            Mainbody.setLocationAndAngles(this.posX, this.posY, this.posZ, 0, 0);
            Oredeposit.onUpdate();
            Oredeposit.setLocationAndAngles(this.posX + 1, this.posY + 4, this.posZ, 0, 0);
        }
        this.bossInfo.setPercent(this.getHealth() / this.getMaxHealth());
    }
}

 

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

Link to comment
Share on other sites

  • 2 weeks later...

I fixed  the ai. I forgot to call super.onLivingUpdate. Still The Hitboxes aren't showing.

My Entity code:

package com.cruelar.cruelars_triforcemod.entities.boss;

import com.cruelar.cruelars_triforcemod.Cruelars_Triforcemod_Core;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BossInfo;
import net.minecraft.world.BossInfoServer;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class Stone_Talus extends EntityMob implements IEntityMultiPart {

    public static final ResourceLocation LOOT = new ResourceLocation("cruelars_triforcemod:entities/stone_talus");
    public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("cruelars_triforcemod:textures/entity/stone_talus.png");
    private final BossInfoServer bossInfo;
    public MultiPartEntityPart[] talusParts;
    public MultiPartEntityPart Mainbody;
    public MultiPartEntityPart Oredeposit;
    public float prevAnimTime;
    public float animTime;

    public Stone_Talus(World world) {
        super(world);
        this.setSize(2.0F, 5F);
        this.isNonBoss();
        this.bossInfo = (BossInfoServer) (new BossInfoServer(this.getDisplayName(), BossInfo.Color.RED, BossInfo.Overlay.PROGRESS));
        this.isImmuneToFire = true;
        this.Mainbody= new MultiPartEntityPart(this, "mainbody", 2, 2);
        this.Oredeposit = new MultiPartEntityPart(this, "oredeposit", 1, 1);
        this.talusParts=new MultiPartEntityPart[]{this.Oredeposit,this.Mainbody};
    }

    public void readEntityFromNBT(NBTTagCompound p_readEntityFromNBT_1_) {
        super.readEntityFromNBT(p_readEntityFromNBT_1_);
        if (this.hasCustomName()) {
            this.bossInfo.setName(this.getDisplayName());
        }

    }

    protected void updateAITasks() {
        super.updateAITasks();

    }

    public void addTrackingPlayer(EntityPlayerMP p_addTrackingPlayer_1_) {
            float distance = p_addTrackingPlayer_1_.getDistance(this);
            if (distance<=10) {

        super.addTrackingPlayer(p_addTrackingPlayer_1_);
        this.bossInfo.addPlayer(p_addTrackingPlayer_1_);
        }
    }

    public void removeTrackingPlayer(EntityPlayerMP p_removeTrackingPlayer_1_) {
        super.removeTrackingPlayer(p_removeTrackingPlayer_1_);
        this.bossInfo.removePlayer(p_removeTrackingPlayer_1_);
    }

    public void setCustomNameTag(String p_setCustomNameTag_1_) {
        super.setCustomNameTag(p_setCustomNameTag_1_);
        this.bossInfo.setName(this.getDisplayName());
    }

    @Override
    protected void entityInit() {
        super.entityInit();
    }

    @Override
    protected void applyEntityAttributes() {
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(300.0D);
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.1D);
        this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(32.0D);
        this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(100.0D);
    }

    @Override
    protected void initEntityAI() {
        this.tasks.addTask(2, new EntityAIAttackMelee(this, 1.0D, true));
        this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 1.0D));
        this.tasks.addTask(7, new EntityAIWander(this, 1.0D));
        this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(8, new EntityAILookIdle(this));
        this.applyEntityAI();
    }

    private void applyEntityAI() {
        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityPlayer.class, true));
    }

    @Override
    public boolean attackEntityAsMob(Entity entity) {
        return super.attackEntityAsMob(entity);
    }

    @Override
    @Nonnull
    protected ResourceLocation getLootTable() {
        return LOOT;
    }

    @Override
    protected boolean isValidLightLevel() {
        return true;
    }

    @Override
    protected boolean canDropLoot() {
        return true;
    }

    @Override
    public int getMaxSpawnedInChunk() {
        return 1;
    }

    @Override
    public boolean isNonBoss() {
        return false;
    }

    @Override
    public World getWorld() {
        return this.world;
    }

    public boolean attackEntityFrom(DamageSource source, float amount)
    {
        if (source instanceof EntityDamageSource && ((EntityDamageSource)source).getIsThornsDamage())
        {
            this.attackEntityFromPart(this.Oredeposit, source, amount);
        }
        this.attackEntityFromPart(this.Oredeposit, source, amount);
        return true;
    }

    protected boolean attackTalusFrom(DamageSource source, float amount)
    {
        return super.attackEntityFrom(source, amount);
    }

    @Override
    public void onLivingUpdate() {
        super.onLivingUpdate();
        if (this.world.isRemote) {
            if (this.talusParts[0]==null||this.talusParts[1]==null){
                this.talusParts = new MultiPartEntityPart[]{this.Mainbody= new MultiPartEntityPart(this, "mainbody", 5, 5), this.Oredeposit = new MultiPartEntityPart(this, "oredeposit", 1, 1)};
            }
            this.setHealth(this.getHealth());
        }else{
            this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);
            Vec3d vec3d3 = (new Vec3d(this.motionX, this.motionY, this.motionZ)).normalize();
            float f10 = 0.8F + 0.15F * 0.1F;
            this.motionX *= (double)f10;
            this.motionZ *= (double)f10;
            this.motionY *= 0.9100000262260437D;
            Vec3d[] avec3d = new Vec3d[this.talusParts.length];
            for (int j = 0; j < this.talusParts.length; ++j)
            {
                avec3d[j] = new Vec3d(this.talusParts[j].posX, this.talusParts[j].posY, this.talusParts[j].posZ);
            }
            this.prevAnimTime = this.animTime;
            if (this.getHealth() <= 0.0F) {
                float f12 = (this.rand.nextFloat() - 0.5F) * 8.0F;
                float f13 = (this.rand.nextFloat() - 0.5F) * 4.0F;
                float f15 = (this.rand.nextFloat() - 0.5F) * 8.0F;
                this.world.spawnParticle(EnumParticleTypes.SPELL_MOB_AMBIENT, this.posX + (double) f12, this.posY + 2.0D + (double) f13, this.posZ + (double) f15, 0.0D, 0.0D, 0.0D);
            }else {
                if (this.isAIDisabled()) {
                    this.animTime = 0.5F;
                } else {
                    Mainbody.onUpdate();
                    Mainbody.setLocationAndAngles(this.posX, this.posY, this.posZ, 0, 0);
                    Oredeposit.onUpdate();
                    Oredeposit.setLocationAndAngles(this.posX + 1, this.posY + 2, this.posZ, 0, 0);
                    for (int l = 0; l < this.talusParts.length; ++l) {
                        this.talusParts[l].prevPosX = avec3d[l].x;
                        this.talusParts[l].prevPosY = avec3d[l].y;
                        this.talusParts[l].prevPosZ = avec3d[l].z;
                    }
                }
                this.bossInfo.setPercent(this.getHealth() / this.getMaxHealth());
            }
        }
    }

    @Override
    public void onKillCommand()
    {
        this.setDead();
    }

    @Nullable
    @Override
    public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
    {
        this.Mainbody= new MultiPartEntityPart(this, "mainbody", 2, 2);
        this.Oredeposit = new MultiPartEntityPart(this, "oredeposit", 1, 1);
        this.talusParts = new MultiPartEntityPart[]{this.Mainbody, this.Oredeposit};
        return livingdata;
    }

    public Entity[] getParts()
    {
        return this.talusParts;
    }

    public boolean attackEntityFromPart(MultiPartEntityPart talusPart, DamageSource source, float damage)
    {

        if (damage < 0.01F)
        {
            return false;
        }
        else
        {
            if (source.getTrueSource() instanceof EntityPlayer || source.isExplosion())
            {
                float f = this.getHealth();
                this.attackTalusFrom(source, damage);

                
            }
            return true;
        }
    }
}

 

Edited by _Cruelar_
typo

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.