/// <summary> /// honk on world click /// </summary> protected override void ServerPerformInteraction(PositionalHandApply interaction) { bool inCloseRange = PlayerScript.IsInReach(interaction.TargetVector); var targetHealth = interaction.TargetObject.GetComponent <LivingHealthBehaviour>(); bool isCrit = Random.Range(0f, 1f) <= CritChance; // honking in someone's face if (inCloseRange && (targetHealth != null)) { interaction.Performer.GetComponent <WeaponNetworkActions>().RpcMeleeAttackLerp(interaction.TargetVector, this.gameObject); PostToChatMessage.SendAttackMessage(interaction.Performer, interaction.TargetObject, isCrit ? 100 : 1, BodyPartType.None, this.gameObject); ClassicHonk(); if (isCrit) { StartCoroutine(CritHonk(interaction, targetHealth)); } } else { ClassicHonk(); } StartCoroutine(StartCooldown()); }
public void CmdRequestPunchAttack(GameObject victim, Vector2 punchDirection, BodyPartType damageZone) { var victimHealth = victim.GetComponent <LivingHealthBehaviour>(); var victimRegisterTile = victim.GetComponent <RegisterTile>(); var rng = new System.Random(); if (!playerScript.IsInReach(victim, true) || !victimHealth) { return; } // If the punch is not self inflicted, do the simple lerp attack animation. if (victim != gameObject) { RpcMeleeAttackLerp(punchDirection, null); playerMove.allowInput = false; } // This is based off the alien/humanoid/attack_hand punch code of TGStation's codebase. // Punches have 90% chance to hit, otherwise it is a miss. if (90 >= rng.Next(1, 100)) { // The punch hit. victimHealth.ApplyDamage(gameObject, (int)fistDamage, AttackType.Melee, DamageType.Brute, damageZone); if (fistDamage > 0) { PostToChatMessage.SendAttackMessage(gameObject, victim, (int)fistDamage, damageZone); } // Make a random punch hit sound. SoundManager.PlayNetworkedAtPos("Punch#", victimRegisterTile.WorldPosition); StartCoroutine(AttackCoolDown()); } else { // The punch missed. string victimName = victim.Player()?.Name; SoundManager.PlayNetworkedAtPos("PunchMiss", transform.position); ChatRelay.Instance.AddToChatLogServer(new ChatEvent { channels = ChatChannel.Local, message = $"{gameObject.Player()?.Name} has attempted to punch {victimName}!" }); } }
/// <summary> /// Invoked when BulletColliderBehavior passes the event up to us. /// </summary> public void HandleTriggerEnter2D(Collider2D coll) { //only harm others if it's not a suicide if (coll.gameObject == shooter && !isSuicide) { return; } //only harm the shooter if it's a suicide if (coll.gameObject != shooter && isSuicide) { return; } //body or object? var livingHealth = coll.GetComponent <LivingHealthBehaviour>(); var integrity = coll.GetComponent <Integrity>(); if (integrity != null) { //damage object integrity.ApplyDamage(damage, attackType, damageType); PostToChatMessage.SendAttackMessage(shooter, coll.gameObject, damage, BodyPartType.None, weapon.gameObject); Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms, integrity.gameObject.name, damage); } else { //damage human if there is one if (livingHealth == null || livingHealth.IsDead) { return; } // Trigger for things like stuns GetComponent <BulletHitTrigger>()?.BulletHitInteract(coll.gameObject); var aim = isSuicide ? bodyAim : bodyAim.Randomize(); livingHealth.ApplyDamage(shooter, damage, attackType, damageType, aim); PostToChatMessage.SendAttackMessage(shooter, coll.gameObject, damage, aim, weapon.gameObject); Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms, livingHealth.gameObject.name, damage); } ReturnToPool(); }
public void CmdRequestMeleeAttack(GameObject victim, GameObject weapon, Vector2 stabDirection, BodyPartType damageZone, LayerType layerType) { if (!playerMove.allowInput || playerScript.IsGhost || !victim || !playerScript.playerHealth.serverPlayerConscious ) { return; } if (!allowAttack) { return; } ItemAttributes weaponAttr = weapon.GetComponent <ItemAttributes>(); // If Tilemap LayerType is not None then it is a tilemap being attacked if (layerType != LayerType.None) { TileChangeManager tileChangeManager = victim.GetComponent <TileChangeManager>(); MetaTileMap metaTileMap = victim.GetComponentInChildren <MetaTileMap>(); if (tileChangeManager == null) { return; } //Tilemap stuff: var tileMapDamage = metaTileMap.Layers[layerType].GetComponent <TilemapDamage>(); if (tileMapDamage != null) { //Wire cutters should snip the grills instead: if (weaponAttr.itemName == "wirecutters" && tileMapDamage.Layer.LayerType == LayerType.Grills) { tileMapDamage.WireCutGrill((Vector2)transform.position + stabDirection); StartCoroutine(AttackCoolDown()); return; } tileMapDamage.DoMeleeDamage((Vector2)transform.position + stabDirection, gameObject, (int)weaponAttr.hitDamage); playerMove.allowInput = false; RpcMeleeAttackLerp(stabDirection, weapon); StartCoroutine(AttackCoolDown()); return; } return; } //This check cannot be used with TilemapDamage as the transform position is always far away if (!playerScript.IsInReach(victim, true)) { return; } // Consider moving this into a MeleeItemTrigger for knifes //Meaty bodies: LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>(); if (victimHealth != null && victimHealth.IsDead && weaponAttr.itemType == ItemType.Knife) { if (victim.GetComponent <SimpleAnimal>()) { SimpleAnimal attackTarget = victim.GetComponent <SimpleAnimal>(); RpcMeleeAttackLerp(stabDirection, weapon); playerMove.allowInput = false; attackTarget.Harvest(); SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position); } else { PlayerHealth attackTarget = victim.GetComponent <PlayerHealth>(); RpcMeleeAttackLerp(stabDirection, weapon); playerMove.allowInput = false; attackTarget.Harvest(); SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position); } } if (victim != gameObject) { RpcMeleeAttackLerp(stabDirection, weapon); playerMove.allowInput = false; } var integrity = victim.GetComponent <Integrity>(); if (integrity != null) { //damaging an object integrity.ApplyDamage((int)weaponAttr.hitDamage, AttackType.Melee, weaponAttr.damageType); } else { //damaging a living thing victimHealth.ApplyDamage(gameObject, (int)weaponAttr.hitDamage, AttackType.Melee, weaponAttr.damageType, damageZone); } SoundManager.PlayNetworkedAtPos(weaponAttr.hitSound, transform.position); if (weaponAttr.hitDamage > 0) { PostToChatMessage.SendAttackMessage(gameObject, victim, (int)weaponAttr.hitDamage, damageZone, weapon); } StartCoroutine(AttackCoolDown()); }