using System.Collections.Generic; using System.Xml.Linq; public class MinEventActionMadmanExplosion : MinEventActionTargetedBase { public static FastTags explosionTag = FastTags.Parse("explosion"); public static Dictionary hitEntities = new Dictionary(); float _initialForceStrength = 40f; Vector2Int _XZMultiplier = new Vector2Int(4, 10); // side to side range - x and z coord Vector2Int _heightMultiplier = new Vector2Int(6, 10); // y coord int blastPower = 0; int blockDamage = 0; int blockRadius = 0; int entityDamage = 0; int entityRadius = 0; int ParticleIndex = 13; int explosionType = 0; int ignoreHeatmap = 0; string blockTags = ""; string particleName = ""; string impactPosition = ""; string soundName = ""; ExplosionData explosionData; Vector3 TargetPos = Vector3.zero; public int SourceEntityID; public EntityAlive SourceEntity; public bool IsNPC = false; public override void Execute(MinEventParams _params) { var entityAlive = _params.Self as EntityAlive; //Log.Out($"MinEventActionMadmanExplosion::Execute - this Entity: {entityAlive}, other: {_params.Other}, others: {_params.Others}"); if (entityAlive == null) return; EntityNPCRebirth npc = entityAlive as EntityNPCRebirth; if (npc != null) { IsNPC = true; //Log.Out($"Npc initiated explosion: {npc}"); } SourceEntity = entityAlive; SourceEntityID = entityAlive.entityId; int entityId = EntityClass.FromString("FuriousRamsayNoEarthDamage"); DynamicProperties properties = EntityClass.list[entityId].Properties; ExplosionData tmpExplosionData = new ExplosionData(properties); bool ignore = false; if (ignoreHeatmap == 1) { ignore = true; } explosionData = new ExplosionData { BlastPower = blastPower, BlockDamage = (float)blockDamage, BlockRadius = (float)blockRadius, BlockTags = blockTags, EntityDamage = (float)entityDamage, EntityRadius = entityRadius, ParticleIndex = ParticleIndex, damageMultiplier = tmpExplosionData.damageMultiplier, IgnoreHeatMap = ignore }; ItemValue itemExplosion = null; if (explosionType == 1) { itemExplosion = ItemClass.GetItem("thrownGrenadeContact", false); } else if (explosionType == 9997) { itemExplosion = ItemClass.GetItem("otherExplosion2", false); } else if (explosionType == 9998) { itemExplosion = ItemClass.GetItem("otherExplosion", false); } else if (explosionType == 9999) { itemExplosion = ItemClass.GetItem("auraExplosion", false); } else if (explosionType == 9996) { itemExplosion = ItemClass.GetItem("auraExplosion2", false); } //Log.Out("MinEventActionMadmanExplosion-Execute instigatorId: " + _params.Buff.instigatorId); //Log.Out("MinEventActionMadmanExplosion-Execute instigatorId: " + _params.Buff.instigatorPos); if (_params.Buff.instigatorId != -1) { //Log.Out("MinEventActionMadmanExplosion-Execute 1"); TargetPos = _params.Position; } else if (_params.Other != null) { //Log.Out("MinEventActionMadmanExplosion-Execute 2"); TargetPos = _params.Other.position; } else { //Log.Out("MinEventActionMadmanExplosion-Execute 2"); TargetPos = _params.Position; } if (blastPower == 201) { RebirthUtilities.InstantiateParticleEffect(particleName, impactPosition, soundName, _params.Self, TargetPos); //Log.Out($"InstantiateParticleEffect: {particleName}, impactPosition: {impactPosition}, TargetPos: {TargetPos}"); } Explode(itemExplosion); } public override bool ParseXmlAttribute(XAttribute _attribute) { var flag = base.ParseXmlAttribute(_attribute); if (flag) return true; var name = _attribute.Name.LocalName; if (string.IsNullOrEmpty(name)) { return flag; } else if (name == "blastPower") { blastPower = Int32.Parse(_attribute.Value); return true; } else if (name == "blockDamage") { blockDamage = Int32.Parse(_attribute.Value); return true; } else if (name == "blockRadius") { blockRadius = Int32.Parse(_attribute.Value); return true; } else if (name == "entityDamage") { entityDamage = Int32.Parse(_attribute.Value); return true; } else if (name == "entityRadius") { entityRadius = Int32.Parse(_attribute.Value); return true; } else if (name == "ParticleIndex") { ParticleIndex = Int32.Parse(_attribute.Value); return true; } else if (name == "explosionType") { explosionType = Int32.Parse(_attribute.Value); return true; } else if (name == "blockTags") { blockTags = _attribute.Value; return true; } else if (name == "ignoreHeatmap") { ignoreHeatmap = Int32.Parse(_attribute.Value); return true; } else if (name == "particleName") { particleName = _attribute.Value; return true; } else if (name == "impactPosition") { impactPosition = _attribute.Value; return true; } else if (name == "soundName") { soundName = _attribute.Value; return true; } else { return false; } } public void Explode(ItemValue _itemValueExplosionSource) { //Log.Out($"MadmanExplosion::AttackEntities - _entityThatCausedExplosion: {SourceEntityID}, _itemValueExplosionSource: {_itemValueExplosionSource}, damageType: {damageType}"); FastTags tags = explosionTag; if (_itemValueExplosionSource != null) { ItemClass itemClass = _itemValueExplosionSource.ItemClass; tags |= itemClass.ItemTags; } float value = EffectManager.GetValue(PassiveEffects.ExplosionEntityDamage, _itemValueExplosionSource, explosionData.EntityDamage, SourceEntity, null, tags); float value2 = EffectManager.GetValue(PassiveEffects.ExplosionRadius, _itemValueExplosionSource, explosionData.EntityRadius, SourceEntity, null, tags); int layerMask = -295563285;// ~(1 << 2 | 1 << 4 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 15 | 1 << 16 | 1 << 18 | 1 << 19 | 1 << 20 | 1 << 23 | 1 << 24 | 1 << 28); // -18739221; int prevLayer = SourceEntity.GetModelLayer(); SourceEntity.SetModelLayer(2, true); Collider[] allColliders = Physics.OverlapSphere(TargetPos - Origin.position, value2, layerMask);// -538480645); //Log.Out($"Found allColliders: {allColliders.Length}, layerMask: {layerMask}"); SourceEntity.SetModelLayer(prevLayer, true); bool flag = false; foreach (Collider collider in allColliders) { if (collider == null) { continue; } Transform transform = collider.transform; string tag = transform.tag; if (!tag.StartsWith("E_BP_")) { continue; } flag = true; Transform hitRootTransform = GameUtils.GetHitRootTransform(tag, transform); EntityAlive entityAlive2 = (hitRootTransform ? hitRootTransform.GetComponent() : null); if (entityAlive2 == null || entityAlive2.entityId == SourceEntityID) { continue; } entityAlive2.ConditionalTriggerSleeperWakeUp(); Vector3 vector = transform.position + Origin.position - TargetPos; float magnitude = vector.magnitude; vector.Normalize(); // check for collision with terrain layer 16 if (Voxel.Raycast(GameManager.Instance.World, new Ray(TargetPos, vector), magnitude, 65536, 66, 0f)) { continue; } EntityClass entityClass = EntityClass.list[entityAlive2.entityClass]; float num = ((!transform.CompareTag("E_BP_LArm") && !transform.CompareTag("E_BP_RArm")) ? ((transform.CompareTag("E_BP_LLeg") || transform.CompareTag("E_BP_RLeg")) ? entityClass.LegsExplosionDamageMultiplier : ((!transform.CompareTag("E_BP_Head")) ? entityClass.ChestExplosionDamageMultiplier : entityClass.HeadExplosionDamageMultiplier)) : entityClass.ArmsExplosionDamageMultiplier); float num2 = value * num; num2 *= 1f - magnitude / value2; num2 = (int)EffectManager.GetValue(PassiveEffects.ExplosionIncomingDamage, null, num2, entityAlive2); if (num2 >= 3f) { if (!hitEntities.TryGetValue(entityAlive2.entityId, out var value3)) { value3.entity = entityAlive2; } EnumBodyPartHit enumBodyPartHit = DamageSource.TagToBodyPart(tag); if (num2 > value3.damage) { value3.damage = num2; value3.dir = vector; value3.hitTransform = transform; value3.mainPart = enumBodyPartHit; } value3.parts |= enumBodyPartHit; hitEntities[entityAlive2.entityId] = value3; } } foreach (KeyValuePair hitEntity in hitEntities) { EntityAlive entity = hitEntity.Value.entity; if (entity == null) { continue; } bool bIsDead = entity.IsDead(); int health = entity.Health; bool bCrit = hitEntity.Value.damage > (float)entity.GetMaxHealth() * 0.1f; EnumBodyPartHit mainPart = hitEntity.Value.mainPart; EnumBodyPartHit parts = hitEntity.Value.parts; parts &= ~mainPart; float num3 = (bIsDead ? 0.85f : 0.6f); for (int j = 0; j < 11; j++) { int num4 = 1 << j; if (((uint)parts & (uint)num4) != 0 && entity.rand.RandomFloat <= num3) { parts = (EnumBodyPartHit)((int)parts & ~num4); } } DamageSourceEntity damageSourceEntity = new DamageSourceEntity(EnumDamageSource.External, EnumDamageTypes.KnockDown, SourceEntityID, hitEntity.Value.dir, hitEntity.Value.hitTransform.name, Vector3.zero, Vector2.zero); damageSourceEntity.bodyParts = mainPart | parts; damageSourceEntity.AttackingItem = _itemValueExplosionSource; damageSourceEntity.DismemberChance = (bCrit ? 0.5f : 0f); int dmgDone = entity.DamageEntity(damageSourceEntity, (int)hitEntity.Value.damage, bCrit); if (dmgDone > 0) { Vector3 force = GetRandomForce(); entity.emodel.DoRagdoll(1f, EnumBodyPartHit.LowerLegs, force, Vector3.zero, entity.isEntityRemote); } //Log.Out($"entity: {entity}, hitEntity.Value.damage: {hitEntity.Value.damage}, bCrit: {bCrit}, dmgDone: {dmgDone}, dmg source entity id: {SourceEntityID}, {SourceEntity}"); if (SourceEntity != null) { MinEventTypes eventType = ((health != entity.Health) ? MinEventTypes.onSelfExplosionDamagedOther : MinEventTypes.onSelfExplosionAttackedOther); SourceEntity.MinEventContext.Self = SourceEntity; SourceEntity.MinEventContext.Other = entity; SourceEntity.MinEventContext.ItemValue = _itemValueExplosionSource; _itemValueExplosionSource?.FireEvent(eventType, SourceEntity.MinEventContext); SourceEntity.FireEvent(eventType, useInventory: false); } if (explosionData.BuffActions != null) { for (int k = 0; k < explosionData.BuffActions.Count; k++) { BuffClass buff = BuffManager.GetBuff(explosionData.BuffActions[k]); if (buff != null) { float originalValue = 1f; originalValue = EffectManager.GetValue(PassiveEffects.BuffProcChance, null, originalValue, SourceEntity, null, FastTags.Parse(buff.Name)); if (entity.rand.RandomFloat <= originalValue) { entity.Buffs.AddBuff(explosionData.BuffActions[k], SourceEntityID); } } } } if (bIsDead || !entity.IsDead()) { continue; } AddKillExp(entity); if (SourceEntity != null) { if (SourceEntity.isEntityRemote) { SingletonMonoBehaviour.Instance.SendPackage(NetPackageManager.GetPackage().Setup(SourceEntity.entityId, entity.entityId, MinEventTypes.onSelfKilledOther, _itemValueExplosionSource), _onlyClientsAttachedToAnEntity: false, SourceEntity.entityId); } else { SourceEntity.FireEvent(MinEventTypes.onSelfKilledOther); } } } if (!flag && SourceEntity != null) { if (SourceEntity.isEntityRemote) { SingletonMonoBehaviour.Instance.SendPackage(NetPackageManager.GetPackage().Setup(SourceEntity.entityId, -1, MinEventTypes.onSelfExplosionMissEntity, _itemValueExplosionSource), _onlyClientsAttachedToAnEntity: false, SourceEntity.entityId); } else { SourceEntity.MinEventContext.Self = SourceEntity; SourceEntity.MinEventContext.Other = null; SourceEntity.MinEventContext.ItemValue = _itemValueExplosionSource; SourceEntity.FireEvent(MinEventTypes.onSelfExplosionMissEntity); } } hitEntities.Clear(); } public void AddKillExp(EntityAlive entity) { EntityPlayer entityPlayer = SourceEntity as EntityPlayer; if (entityPlayer == null && IsNPC) { EntityNPCRebirth npc = SourceEntity as EntityNPCRebirth; int leader = (int)npc.Buffs.GetCustomVar("$Leader", 0); //entityPlayer = npc.Owner; if (entityPlayer == null && leader > 0) entityPlayer = GameManager.Instance.World.GetEntity(leader) as EntityPlayer; //Log.Out($"Found leader: {leader}, npc owner: {entityPlayer}"); } if (entityPlayer != null) { entityPlayer.AddKillXP(entity); } } public Vector3 GetRandomForce() { int xSign = UnityEngine.Random.Range(0, 2) * 2 - 1; // randomly go in the negative direction int zSign = UnityEngine.Random.Range(0, 2) * 2 - 1; int xStr = UnityEngine.Random.Range(_XZMultiplier.x, _XZMultiplier.y) * xSign; int yStr = UnityEngine.Random.Range(_heightMultiplier.x, _heightMultiplier.y); int zStr = UnityEngine.Random.Range(_XZMultiplier.x, _XZMultiplier.y) * zSign; Vector3 force = new Vector3(_initialForceStrength * xStr, _initialForceStrength * yStr, _initialForceStrength * zStr); //Log.Out($"force: {force}"); return force; } public struct DamageRecord { public EntityAlive entity; public float damage; public Vector3 dir; public Transform hitTransform; public EnumBodyPartHit mainPart; public EnumBodyPartHit parts; } }