//use expectedDamage() to initiate the chainAttack object and send warnings to everything public override void expectedDamage(ref DamageEventData d) { //spawn a chainAttack object. We borrow a prefab reference from the level manager since we cant have one of our own attackObject = ((GameObject)GameObject.Instantiate(LevelManagerScript.instance.chainAttackPrefab)).GetComponent <ChainAttackScript>(); //set the attack color, if there is one if (d.effects.propertyEffects.attackColor != null) { attackObject.lineRenderer.startColor = d.effects.propertyEffects.attackColor.Value; attackObject.lineRenderer.endColor = d.effects.propertyEffects.attackColor.Value / 2; } //create a DamageEventData for the attack object to base its attacks on DamageEventData baseEvent = new DamageEventData(); baseEvent.dest = null; baseEvent.rawDamage = d.rawDamage; baseEvent.source = d.source; //the chained attack contains all effects except for this one baseEvent.effects = d.effects.clone(); baseEvent.effects.removeEffect("chainHit"); //have it spread warnings around to everything that will get hit attackObject.ChainAttackWarn(baseEvent, d.dest, strength, targetCap); }
private void OnHit(AttackEventData data, DeferredMessageContext messageContext) { var damageData = new DamageEventData { Damage = data.Damage.Value, DamagedBy = data.Attacker }; var damaged = _systemContainer.EventSystem.Try(EventType.Damage, data.Defender, damageData); if (damaged) { DescribeSuccessfulAttack(data, messageContext, damageData.Damage); } else { if (string.IsNullOrEmpty(data.SuccessfulDefenceType)) { if (damageData.Absorbed) { data.SuccessfulDefenceType = "Absorbed"; } else { data.SuccessfulDefenceType = "NoDamage"; } } DescribeMissedAttack(data, messageContext); } }
} //default constructor inits internal variables to 0 public override void UpdateEnemy(EnemyScript e, float deltaTime) { //do nothing if the effect time is already over if (curPoisonTime > maxPoisonTime) { return; } //update timer curPoisonTime += Time.deltaTime; //calculate damage float damage = (strength * Time.deltaTime) + carryOver; int roundedDamage = Mathf.FloorToInt(damage); carryOver = damage - roundedDamage; //return early if zero damage if (roundedDamage == 0) { return; } //construct event DamageEventData damageEvent = new DamageEventData(); damageEvent.source = effectSource; damageEvent.dest = e; damageEvent.rawDamage = roundedDamage; damageEvent.effects = null; //deal damage e.onExpectedDamage(ref damageEvent); e.onDamage(damageEvent, false); //hide particles from poison damage }
// Get Damage Event Data (to use only on Damage Event Script) public static DamageEventData GetDamageEventData() { Internal.NativeFunctions.nwnxSetFunction(PLUGIN_NAME, "GetDamageEventData"); Internal.NativeFunctions.nwnxCallFunction(); var data = new DamageEventData { Damager = Internal.NativeFunctions.nwnxPopObject(), Bludgeoning = Internal.NativeFunctions.nwnxPopInt(), Pierce = Internal.NativeFunctions.nwnxPopInt(), Slash = Internal.NativeFunctions.nwnxPopInt(), Magical = Internal.NativeFunctions.nwnxPopInt(), Acid = Internal.NativeFunctions.nwnxPopInt(), Cold = Internal.NativeFunctions.nwnxPopInt(), Divine = Internal.NativeFunctions.nwnxPopInt(), Electrical = Internal.NativeFunctions.nwnxPopInt(), Fire = Internal.NativeFunctions.nwnxPopInt(), Negative = Internal.NativeFunctions.nwnxPopInt(), Positive = Internal.NativeFunctions.nwnxPopInt(), Sonic = Internal.NativeFunctions.nwnxPopInt(), Base = Internal.NativeFunctions.nwnxPopInt() }; return(data); }
private static void HandleWeaponStatBonuses() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWPlayer player = data.Damager.Object; NWItem weapon = _.GetLastWeaponUsed(player); if (weapon.CustomItemType == CustomItemType.BlasterPistol || weapon.CustomItemType == CustomItemType.BlasterRifle) { int statBonus = (int)(player.DexterityModifier * 0.5f); data.Base += statBonus; } else if (weapon.CustomItemType == CustomItemType.Lightsaber || weapon.CustomItemType == CustomItemType.Saberstaff || weapon.GetLocalInt("LIGHTSABER") == TRUE) { int statBonus = (int)(player.CharismaModifier * 0.25f); data.Base += statBonus; } NWNXDamage.SetDamageEventData(data); }
//we dont need to do anything on expected damage public override void expectedDamage(ref DamageEventData d) { if (innerEffect.triggersAs(EffectType.enemyDamaged)) { base.expectedDamage(ref d); } } //pass to child if it is also an enemyDamaged effect
public virtual void trigger(ref DamageEventData d, int pointsOfOvercharge) { if (shouldApplyInnerEffect()) { ((IEffectOvercharge)innerEffect).trigger(ref d, pointsOfOvercharge); } }
private static void HandleTranquilizerEffect() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWObject self = NWGameObject.OBJECT_SELF; // Ignore the first damage because it occurred during the application of the effect. if (self.GetLocalInt("TRANQUILIZER_EFFECT_FIRST_RUN") > 0) { self.DeleteLocalInt("TRANQUILIZER_EFFECT_FIRST_RUN"); return; } for (Effect effect = _.GetFirstEffect(self.Object); _.GetIsEffectValid(effect) == TRUE; effect = _.GetNextEffect(self.Object)) { if (_.GetEffectTag(effect) == "TRANQUILIZER_EFFECT") { _.RemoveEffect(self, effect); } } }
private static void HandleStances() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWPlayer damager = data.Damager.Object; NWItem damagerWeapon = _.GetLastWeaponUsed(damager); if (damager.IsPlayer) { CustomEffectType stance = CustomEffectService.GetCurrentStanceType(damager); switch (stance) { case CustomEffectType.ShieldOath: data.AdjustAllByPercent(-0.30f); break; case CustomEffectType.PrecisionTargeting: if (damagerWeapon.CustomItemType == CustomItemType.BlasterPistol || damagerWeapon.CustomItemType == CustomItemType.BlasterRifle) { data.AdjustAllByPercent(0.20f); } break; } } NWNXDamage.SetDamageEventData(data); }
private static void HandleRecoveryBlast() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWObject damager = data.Damager; bool isActive = damager.GetLocalInt("RECOVERY_BLAST_ACTIVE") == TRUE; damager.DeleteLocalInt("RECOVERY_BLAST_ACTIVE"); NWItem weapon = _.GetLastWeaponUsed(damager.Object); if (!isActive || weapon.CustomItemType != CustomItemType.BlasterRifle) { return; } data.Bludgeoning = 0; data.Pierce = 0; data.Slash = 0; data.Magical = 0; data.Acid = 0; data.Cold = 0; data.Divine = 0; data.Electrical = 0; data.Fire = 0; data.Negative = 0; data.Positive = 0; data.Sonic = 0; data.Base = 0; NWNXDamage.SetDamageEventData(data); }
private static void OnModuleApplyDamage() { DamageEventData data = NWNXDamage.GetDamageEventData(); NWPlayer player = data.Damager.Object; NWCreature target = NWGameObject.OBJECT_SELF; int attackType = target.GetLocalInt(AbilityService.LAST_ATTACK + player.GlobalID); LoggingService.Trace(TraceComponent.LastAttack, "Last attack from " + player.GlobalID + " on " + _.GetName(target) + " was type " + attackType); if (attackType == AbilityService.ATTACK_PHYSICAL) { // Only apply bonus damage from physical attacks. HandleWeaponStatBonuses(); HandleEvadeOrDeflectBlasterFire(); HandleApplySneakAttackDamage(); } HandleDamageImmunity(); HandleAbsorptionFieldEffect(); HandleRecoveryBlast(); HandleTranquilizerEffect(); HandleStances(); }
//recalculate speed public override void actualDamage(ref DamageEventData d) { EnemyScript e = d.dest; //enemy reference float healthRatio = (float)e.curHealth / (float)e.maxHealth; //how much health the unit still has (0: dead. 1: full health) e.unitSpeed = Mathf.CeilToInt(e.unitSpeedWhenSpawned * (healthRatio / strength)); //scale e.unitSpeed = Mathf.Min(e.unitSpeed, 1.0f); //enforce minimum }
protected override void PrepareEvent(NwObject objSelf) { DamageEventData eventData = DamagePlugin.GetDamageEventData(); DamageData = DamageData.FromNative(eventData); Attacker = eventData.oDamager.ToNwObject <NwGameObject>(); Target = (NwGameObject)objSelf; }
public virtual void expectedDamage(ref DamageEventData d) { if (shouldApplyInnerEffect()) { enemyDamageEFfectTriggers++; ((IEffectEnemyDamaged)innerEffect).expectedDamage(ref d); } }
public virtual void actualDamage(ref DamageEventData d) { if (enemyDamageEFfectTriggers > 0) { enemyDamageEFfectTriggers--; ((IEffectEnemyDamaged)innerEffect).actualDamage(ref d); } }
protected virtual void Attack(float _damage) { print("Attacking... and doing " + _damage + " points of damage"); damageEventData = new DamageEventData(EventSystem.current); damageEventData.Initialize(_damage); player.OnDamage(damageEventData); }
//recalculate speed public override void actualDamage(ref DamageEventData d) { EnemyScript e = d.dest; float scaleRatio = 1 - ((float)e.curHealth / (float)e.maxHealth); //ratio we are scaling by float scaleFactor = ((scaleRatio - 1) * strength) + 1; //factor to use for scaling e.unitSpeed = Mathf.RoundToInt(scaleFactor * e.unitSpeedWhenSpawned); //scale }
} //pass to child if it is also an enemyDamaged effect //recalculate effect strength when attacks hit public override void actualDamage(ref DamageEventData d) { if (effectBaseStrength == null) { effectBaseStrength = innerEffect.strength; } scaleInnerEffect(); }
protected void Shoot() { fireAudio.Play(SoundsPlayer.Selection.Randomly, audioSource, 1f); if (muzzleFlash) { muzzleFlash.Play(true); } float spread = spreadAim; RaycastHit hitInfo; var firePos = new Vector3(user.transform.position.x, user.transform.position.y + user.GetComponent <CapsuleCollider>().height / 2, user.transform.position.z); Ray ray = new Ray(firePos, transform.forward); Vector3 spreadVector = user.transform.TransformVector(new Vector3(Random.Range(-spread, spread), Random.Range(-spread, spread), 0f)); ray.direction = Quaternion.Euler(spreadVector) * ray.direction; if (debugVisual) { Debug.DrawLine(firePos, firePos + user.transform.forward * distanceMax, Color.red, 1100); } if (Physics.Raycast(ray, out hitInfo, distanceMax, damageMask, QueryTriggerInteraction.Ignore)) { if (hitInfo.collider.gameObject == user) { return; } float impulse = hitImpact.GetImpulseAtDistance(hitInfo.distance, distanceMax); float damage = hitImpact.GetDamageAtDistance(hitInfo.distance, distanceMax); SpawnHitEffect(hitInfo); SpawnHitSound(hitInfo); var damageable = hitInfo.collider.GetComponent <IDamageable>(); if (damageable != null) { var damageData = new DamageEventData(-damage, user, hitInfo.point, ray.direction, impulse); damageable.TakeDamage(damageData); } else if (hitInfo.rigidbody) { hitInfo.rigidbody.AddForceAtPosition(ray.direction * impulse, hitInfo.point, ForceMode.Impulse); } } if (tracer) { var temp = Instantiate(tracer, transform.position, Quaternion.LookRotation(ray.direction)); Destroy(temp, 1); } }
private static void HandleApplySneakAttackDamage() { DamageEventData data = NWNXDamage.GetDamageEventData(); if (data.Total <= 0) { return; } NWObject damager = data.Damager; int sneakAttackType = damager.GetLocalInt("SNEAK_ATTACK_ACTIVE"); if (damager.IsPlayer && sneakAttackType > 0) { NWPlayer player = damager.Object; NWCreature target = _.OBJECT_SELF; var pcPerk = PerkService.GetPCPerkByID(damager.GlobalID, (int)PerkType.SneakAttack); int perkRank = pcPerk?.PerkLevel ?? 0; int perkBonus = 1; // Rank 4 increases damage bonus by 2x (total: 3x) if (perkRank == 4) { perkBonus = 2; } float perkRate; if (sneakAttackType == 1) // Player is behind target. { perkRate = 1.0f * perkBonus; } else // Player is anywhere else. { perkRate = 0.5f * perkBonus; } var effectiveStats = PlayerStatService.GetPlayerItemEffectiveStats(player); float damageRate = 1.0f + perkRate + effectiveStats.SneakAttack * 0.05f; data.Base = (int)(data.Base * damageRate); if (target.IsNPC) { EnmityService.AdjustEnmity(target, player, 5 * data.Base); } NWNXDamage.SetDamageEventData(data); } damager.DeleteLocalInt("SNEAK_ATTACK_ACTIVE"); }
/// <summary> /// spawns a burstShot to attack all enemies in range /// </summary> /// <param name="targets">list of enemies in range. The burstShot itself will catch enemies that enter the region during the attack</param> /// <param name="damageEvent">details of the attack. damageEvent.dest is ignored.</param> private void burstFire(IEnumerable <EnemyScript> targets, DamageEventData damageEvent) { //construct burst shot event BurstShotData data = new BurstShotData(); data.targetList = targets; data.burstRange = range; data.damageEvent = damageEvent; //create a burst shot and give it the data GameObject shot = Instantiate(burstShotPrefab); //create it shot.transform.position = transform.position; //center it on the tower shot.SendMessage("SetData", data); //initialize it }
/// <summary> /// spawns a directionalShot to attack all enemies in a straight line /// </summary> /// <param name="targets">list of enemies in range. The DirectionalShot itself will find other enemies on its own as it goes by</param> /// <param name="damageEvent">details of the attack. damageEvent.dest is ignored.</param> /// <param name="attackDir">direction the attack should travel</param> private void directionalShot(List <EnemyScript> targets, DamageEventData damageEvent, Vector2 attackDir) { //construct event DirectionalShotData data = new DirectionalShotData(); data.attackDir = attackDir; data.damageEvent = damageEvent; data.targetList = targets; //spawn it GameObject shot = Instantiate(directionalShotPrefab); shot.transform.position = transform.position; //center it on the tower shot.SendMessage("SetData", data); //initialize it }
} //name used to refer to this effect in XML //alter damage calculations when we expect to deal damage, not when it actually happens, so that targeting etc. have an accurate number to work with public override void expectedDamage(ref DamageEventData d) { //skip if the attack ignores armor if (d.effects != null) { if (d.effects.propertyEffects.armorPierce) { return; } } if (d.rawDamage <= 1) { return; //dont bother applying armor if the incoming attack is already at or below the min } d.rawDamage -= strength; //reduce damage by armor value d.rawDamage = Mathf.Max(d.rawDamage, 1.0f); //but must deal at least one }
/// <summary> /// spawns a bullet to attack an enemy unit /// </summary> /// <param name="enemy">the enemy to attack</param> /// <param name="damageEvent">details of the attack the new bullet is meant to perform</param> private void spawnBullet(EnemyScript enemy, DamageEventData damageEvent) { //tell the event who our target is damageEvent.dest = enemy; GameObject bullet = (GameObject)Instantiate(bulletPrefab, transform.position, Quaternion.identity); bullet.SendMessage("InitBullet", damageEvent); //apply attackColor property, if it is present if (effects != null) { if (effects.propertyEffects.attackColor != null) { bullet.SendMessage("SetColor", effects.propertyEffects.attackColor); } } }
// Set Damage Event Data (to use only on Damage Event Script) public static void SetDamageEventData(DamageEventData data) { Internal.NativeFunctions.nwnxSetFunction(PLUGIN_NAME, "SetDamageEventData"); Internal.NativeFunctions.nwnxPushInt(data.Base); Internal.NativeFunctions.nwnxPushInt(data.Sonic); Internal.NativeFunctions.nwnxPushInt(data.Positive); Internal.NativeFunctions.nwnxPushInt(data.Negative); Internal.NativeFunctions.nwnxPushInt(data.Fire); Internal.NativeFunctions.nwnxPushInt(data.Electrical); Internal.NativeFunctions.nwnxPushInt(data.Divine); Internal.NativeFunctions.nwnxPushInt(data.Cold); Internal.NativeFunctions.nwnxPushInt(data.Acid); Internal.NativeFunctions.nwnxPushInt(data.Magical); Internal.NativeFunctions.nwnxPushInt(data.Slash); Internal.NativeFunctions.nwnxPushInt(data.Pierce); Internal.NativeFunctions.nwnxPushInt(data.Bludgeoning); Internal.NativeFunctions.nwnxCallFunction(); }
public virtual void OnHit(HitBox hitBox, Collider other) { if (canApplyDamage && !hitObjctCache[hitBox].Contains(other.gameObject) && (user != null && other.gameObject != user.gameObject)) { hitObjctCache[hitBox].Add(other.gameObject); SpawnHitEffect(other); SpawnHitSound(other); var damageable = other.GetComponent <IDamageable>(); if (damageable != null) { var damageData = new DamageEventData(-hitImpact.GetDamage(), user); damageable.TakeDamage(damageData); } } }
/// Set Damage Event Data /// <param name="data">A NWNX_Damage_DamageEventData struct.</param> /// @note To use only in the Damage Event Script. public static void SetDamageEventData(DamageEventData data) { VM.NWNX.SetFunction(NWNX_Damage, "SetDamageEventData"); VM.NWNX.StackPush(data.oDamager); VM.NWNX.StackPush(data.iBludgeoning); VM.NWNX.StackPush(data.iPierce); VM.NWNX.StackPush(data.iSlash); VM.NWNX.StackPush(data.iMagical); VM.NWNX.StackPush(data.iAcid); VM.NWNX.StackPush(data.iCold); VM.NWNX.StackPush(data.iDivine); VM.NWNX.StackPush(data.iElectrical); VM.NWNX.StackPush(data.iFire); VM.NWNX.StackPush(data.iNegative); VM.NWNX.StackPush(data.iPositive); VM.NWNX.StackPush(data.iSonic); VM.NWNX.StackPush(data.iBase); VM.NWNX.Call(); }
//initializes the attack public void SetData(DirectionalShotData data) { attackDir = data.attackDir; transform.rotation = Quaternion.FromToRotation(Vector2.up, attackDir); baseDamageEvent = data.damageEvent; //put the initial target list on the expected list and inform those enemies foreach (EnemyScript t in data.targetList) { //build event DamageEventData ded = new DamageEventData(); ded.source = baseDamageEvent.source; ded.rawDamage = baseDamageEvent.rawDamage; ded.effects = baseDamageEvent.effects; ded.dest = t; //trigger effects if (ded.effects != null) { foreach (IEffect ie in ded.effects.effects) { if (ie.triggersAs(EffectType.enemyDamaged)) { ((IEffectEnemyDamaged)ie).expectedDamage(ref ded); } } } //warn enemy t.onExpectedDamage(ref ded); expectedToHit.Add(ded); } //play sound int soundToPlay = Random.Range(0, attackSounds.Length); audioSource.clip = attackSounds[soundToPlay]; audioSource.volume = MessageHandlerScript.instance.SFXVolumeSetting; audioSource.Play(); initialized = true; //flag ready }
/// <summary> /// Set Damage Event Data (to use only on Damage Event Script) /// </summary> /// <param name="data"></param> public static void SetDamageEventData(DamageEventData data) { string sFunc = "SetDamageEventData"; NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Base); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Sonic); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Positive); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Negative); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Fire); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Electrical); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Divine); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Cold); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Acid); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Magical); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Slash); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Pierce); NWNXCore.NWNX_PushArgumentInt(NWNX_Damage, sFunc, data.Bludgeoning); NWNXCore.NWNX_CallFunction(NWNX_Damage, sFunc); }
} //pass to child if it is also an enemyDamaged effect //recalculate effect strength public override void actualDamage(ref DamageEventData d) { EnemyScript e = d.dest; //on first hit, cache references if (effectBaseStrength == null) { effectBaseStrength = innerEffect.strength; } float healthRatio = (float)e.curHealth / (float)e.maxHealth; //how much health the unit still has (0: dead. 1: full health) innerEffect.strength = Mathf.CeilToInt(effectBaseStrength.Value * (healthRatio / strength)); //scale innerEffect.strength = Mathf.Max(innerEffect.strength, 1.0f); //enforce minimum if (innerEffect.triggersAs(EffectType.enemyDamaged)) { base.expectedDamage(ref d); //pass to child if it is also an enemyDamaged effect } }