Immersive Engineering

Immersive Engineering

134M Downloads

[Suggestion/PR Discussion] Conversion of Tesla Coils to using an ITeslaEntity Capability

Thutmose opened this issue ยท 7 comments

commented

Current Tesla Coil Behaviour:

  1. Get a list of all nearby entities, within radius + radius/2 (targetsAll)

  2. Filter targetsAll for all nearby living entities within radius (targets)

  3. Select a random member of targets, and hits it for damage

  4. Then foreach in targetsAll, if it is an ITeslaEntity, call onHit, otherwise if LivingEntity, try to apply the effect of the TC_FIELD to it

Proposed Tesla Coil Behaviour:

1. Convert ITeslaEntity to a capability, add an additional method to it

Currently ITeslaEntity, contains a single method, void onHit(TileEntity teslaCoil, boolean lowPower), which the flourescent tubes use to pull energy from the coil and glow.

I propose that onHit be changed to onNear, or similar, as it actually applies from distance, not for them actual arc hit, this method can have default behaviour identical to these lines here:

else if(e instanceof LivingEntity)
IElectricEquipment.applyToEntity((LivingEntity)e, null, TC_FIELD);

Next, I propose an onHit method which is called if the arc actually hits the entity, like in (3) in the current behaviour, the effect of the default for this method can be identical to these lines here:

if(target!=null)
{
if(!world.isRemote)
{
energyDrain = IEConfig.MACHINES.teslacoil_consumption_active.get();
if(lowPower)
energyDrain /= 2;
if(energyStorage.extractEnergy(energyDrain, true)==energyDrain)
{
energyStorage.extractEnergy(energyDrain, false);
if(dmgsrc.apply(target))
{
int prevFire = target.fire;
target.fire = 1;
target.addPotionEffect(new EffectInstance(IEPotions.stunned, 128));
target.fire = prevFire;
}
this.sendRenderPacket(target);
}
}
}

2. Apply this capability to all LivingEntity by default, with a lowest priority event listener

By using lowest priority event listener, this allows doing a check to see if someone else has added a capability handler for this first, before applying the default settings.

If the ITeslaEntity uses the proposed defaults above, then it will behave exactly like the current behaviour for LivingEntitites, and the Flourescent Tube can have a custom implementation as it currently does in the existing onHit

Behaviour after the proposed changes:

  1. Get a list of all nearby entities, within radius + radius/2 (targetsAll)
  2. Filter targetsAll to only contain entities which posses the ITeslaEntity capability
  3. Filter targetsAll for living entities within radius (targets)
  4. Select a random member of targets, and call the new onHit for it
  5. For the remainder in targetsAll, call onNear

Additional Things to discuss:

  • Where should this capability be held? should it be where the sky hooks capability currently is?
  • What arguments should be handed to the new onHit method, should any adjustments be made to the arguments for onNear?
  • Should any other methods be added?
commented

I'm not super sure if I like the idea of applying that capability to all living entities. Beyond that, this seems like a good approach.

commented

hmm, could have an API method which returns an ITeslaEntity when handed an entity, and have that do a capability check, if present, return that, otherwise, return a defaulted case of the capability? that way it doesn't need to be attached to the living entities, except for ones which have custom behaviour?

ie something like:

    public static ITeslaEntity getITeslaEntity(Entity in)
    {
        return in.getCapability(ITESLACAP).orElse(in instanceof LivingEntity? new DefaultTeslaEntity(in): null);
    }

then do a null check after this to see if any effects to apply? or have the DefaultTeslaEntity able to handle non-living entities as well?

commented

Why handle all this in some obscure default implementation of the capability?
The capability should have a void onHit() and boolean shouldTakeDamage().

Then you get the capability from the target entity using entity.getCapability(). That returns an optional. If it's present, you respect shouldTakeDamage(). If it's not present, you just inflict damage. That way, a tesla-immune entity can prevent taking damage. Easy.

commented

the concern is if your entity wants to do something on the standard hit, rather than on just being nearby.

currently "onHit" is more of an "onNearby", and it gets triggered regardless of if one of the arcs actually hits the entity

Having the damage dealt in a custom method call when the mob is actually hit would allow for more easily handling cases where the streamer hits the target, can be used for things like adjusting energy stored in worn items, etc as well as dealing the damage

commented

Okay, do an onNear, onHit and shouldTakeDamage then. But handling the actual damage application in a default capability implementation that needs to be applied to every Entity is a massive waste of resources.
There is zero precedent or usecase for it, over having the damaging be handled by the coil itself.

commented

having shouldTakeDamage would remove the utility of handing the damage in onHit, so shouldTakeDamage would remove the need for a default implementation

commented

Yes, that is exactly what I'm saying.
I don't want a default implementation that gets attached to everything. So if there is no capability, the entity takes damage, and if there is one shouldTakeDamage is called before applying damage. You can cancel it in there if you want, and then run custom damage logic in onHit