About this mod
Updated for U7! It's dangerous to go alone, take this! Bombchu from The Legend of Zelda, place it on the ground and it will move until it hits an enemy, homing on them. Then it explodes. You can find it in "Traps".
- Permissions and credits
- Changelogs
public class ItemBombchu : MonoBehaviour
{
protected Item item;
private Transform bombchuTransform;
private ParticleSystem explosionVFX;
private MeshRenderer mesh;
private Transform targetTransform = null;
private AudioSource explosionSFX;
private AudioSource startRunningSFX;
private AudioSource runningSFX;
private float timeOut = 1f;
private float timerBombchu = 0f;
private bool hasExploded = false;
private bool isBombchuActive = false;
private bool bombchuRun = false;
private bool hasTarget = false;
private bool bombchuTurn = false;
private float distNPC = 0f;
private float expReductor = 0f;
private Vector3 expForceDirection;
private float detectionBubble = 20f;
private float distanceToTarget = 0f;
private float angleToTarget = 0f;
private Vector3 vectorBombchuToTarget;
private Creature nearestTarget;
public float explosionRadius = 5f;
public float expForceMultiplier = 50f;
public float rotationSpeed = 0.2f;
protected void Awake()
{
item = this.GetComponent<Item>();
mesh = item.GetComponentInChildren<MeshRenderer>();
bombchuTransform = item.transform;
explosionVFX = item.GetComponentInChildren<ParticleSystem>();
explosionSFX = item.transform.Find("ExplosionSFX").GetComponent<AudioSource>();
startRunningSFX = item.transform.Find("StartRunningSFX").GetComponent<AudioSource>();
runningSFX = item.transform.Find("RunningSFX").GetComponent<AudioSource>();
item.OnCollisionEvent += OnBombchuCollisionEvent;
item.OnGrabEvent += OnBombchuGrabEvent;
item.OnTeleGrabEvent += OnBombchuTeleGrab;
item.OnUngrabEvent += OnBombchuUngrabEvent;
foreach (Collider col in item.GetComponentsInChildren<Collider>())
{
col.material.frictionCombine = 0f;
col.material.dynamicFriction = 0f;
col.material.staticFriction = 0f;
}
}
void OnBombchuCollisionEvent(ref CollisionStruct collisionInstance)
{
if(collisionInstance.targetType == CollisionStruct.TargetType.NPC && isBombchuActive)
{
Explosion(explosionRadius);
item.enabled = false;
mesh.enabled = false;
hasExploded = true;
}
if (isBombchuActive && !bombchuRun)
{
bombchuRun = true;
startRunningSFX.Play();
}
}
void OnBombchuTeleGrab(Handle handle, Telekinesis teleGrabber)
{
DesactivateBombchu();
}
void OnBombchuGrabEvent(Handle handle, Interactor interactor)
{
DesactivateBombchu();
}
void OnBombchuUngrabEvent(Handle handle, Interactor interactor, bool throwing)
{
isBombchuActive = true;
}
void FixedUpdate()
{
if (bombchuRun)
{
BombchuRun();
}
if (hasExploded)
{
timerBombchu += Time.deltaTime;
}
if(timerBombchu > timeOut)
{
item.Despawn();
}
}
void DesactivateBombchu()
{
bombchuRun = false;
isBombchuActive = false;
runningSFX.Stop();
DeleteTarget();
}
void Explosion(float rad)
{
ExplosionFX();
foreach (Creature npc in Creature.list)
{
if (npc != Creature.player)
{
distNPC = Vector3.Distance(npc.gameObject.transform.position, bombchuTransform.position);
if (distNPC < rad)
{
expReductor = (rad - distNPC) / rad;
expForceDirection = npc.gameObject.transform.position - bombchuTransform.position;
expForceDirection.Normalize();
expForceDirection += Vector3.up;
expForceDirection.Normalize();
if (npc.state != Creature.State.Dead)
{
npc.ragdoll.SetState(BS.Ragdoll.State.Fallen);
}
foreach (RagdollPart ragdollPart in npc.ragdoll.parts)
{
ragdollPart.rb.AddForce(expForceDirection * expForceMultiplier * expReductor, ForceMode.Impulse);
}
npc.health.Kill();
}
}
}
}
void BombchuRun()
{
item.rb.AddForce(bombchuTransform.forward * 10f, ForceMode.Force);
if (!startRunningSFX.isPlaying && !runningSFX.isPlaying && !hasExploded)
{
runningSFX.Play();
}
if (!hasTarget)
{
SetTarget();
}
if (hasTarget && (targetTransform != null))
{
distanceToTarget = Vector3.Distance(bombchuTransform.position, targetTransform.position);
if (distanceToTarget <= detectionBubble)
{
bombchuTurn = true;
}
else
{
bombchuTurn = false;
DeleteTarget();
}
}
if (bombchuTurn)
{
Turn();
}
}
void ExplosionFX()
{
runningSFX.Stop();
explosionVFX.Play();
explosionSFX.Play();
}
void SetTarget()
{
foreach(Creature target in Creature.list)
{
if(target != Creature.player)
{
if(target.state != Creature.State.Dead)
{
if (Vector3.Distance(bombchuTransform.position, target.transform.position) < detectionBubble)
{
vectorBombchuToTarget = target.transform.position - bombchuTransform.position;
vectorBombchuToTarget.y = 0f;
angleToTarget = Vector3.Angle(bombchuTransform.forward, vectorBombchuToTarget);
if (angleToTarget < 90f)
{
nearestTarget = target;
}
}
}
}
}
if (nearestTarget != null)
{
targetTransform = nearestTarget.transform;
hasTarget = true;
}
}
void DeleteTarget()
{
targetTransform = null;
nearestTarget = null;
hasTarget = false;
angleToTarget = 0f;
bombchuTurn = false;
}
void Turn()
{
vectorBombchuToTarget = targetTransform.position - bombchuTransform.position;
vectorBombchuToTarget.y = 0f;
angleToTarget = Vector3.SignedAngle(bombchuTransform.forward, vectorBombchuToTarget, bombchuTransform.up);
if(angleToTarget > 3f)
{
item.transform.Rotate(bombchuTransform.up, rotationSpeed);
}else if(angleToTarget < -3f)
{
item.transform.Rotate(bombchuTransform.up, -1 * rotationSpeed);
}
}
}