public void ServerPerformMeleeAttack(GameObject victim, Vector2 attackDirection, BodyPartType damageZone, LayerType layerType) { if (Cooldowns.IsOnServer(playerScript, CommonCooldowns.Instance.Melee)) { return; } var weapon = playerScript.playerNetworkActions.GetActiveHandItem(); var tiles = victim.GetComponent <InteractableTiles>(); if (tiles) { //validate based on position of target vector if (!Validations.CanApply(playerScript, victim, NetworkSide.Server, targetVector: attackDirection)) { return; } } else { //validate based on position of target object if (!Validations.CanApply(playerScript, victim, NetworkSide.Server)) { return; } } if (!playerMove.allowInput || playerScript.IsGhost || !victim || !playerScript.playerHealth.serverPlayerConscious ) { return; } var isWeapon = weapon != null; ItemAttributesV2 weaponAttr = isWeapon ? weapon.GetComponent <ItemAttributesV2>() : null; var damage = isWeapon ? weaponAttr.ServerHitDamage : fistDamage; var damageType = isWeapon ? weaponAttr.ServerDamageType : DamageType.Brute; var attackSoundName = isWeapon ? weaponAttr.ServerHitSound : "Punch#"; LayerTile attackedTile = null; bool didHit = false; ItemAttributesV2 weaponStats = null; if (isWeapon) { weaponStats = weapon.GetComponent <ItemAttributesV2>(); } // If Tilemap LayerType is not None then it is a tilemap being attacked if (layerType != LayerType.None) { var tileChangeManager = victim.GetComponent <TileChangeManager>(); if (tileChangeManager == null) { return; //Make sure its on a matrix that is destructable } //Tilemap stuff: var tileMapDamage = victim.GetComponentInChildren <MetaTileMap>().Layers[layerType].gameObject .GetComponent <TilemapDamage>(); if (tileMapDamage != null) { if (isWeapon && weaponStats != null && weaponStats.hitSoundSettings == SoundItemSettings.OnlyObject) { attackSoundName = ""; } var worldPos = (Vector2)transform.position + attackDirection; attackedTile = tileChangeManager.InteractableTiles.LayerTileAt(worldPos, true); tileMapDamage.DoMeleeDamage(worldPos, gameObject, (int)damage); didHit = true; } } else { //a regular object being attacked LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>(); var integrity = victim.GetComponent <Integrity>(); if (integrity != null) { //damaging an object if (isWeapon && weaponStats != null && weaponStats.hitSoundSettings == SoundItemSettings.Both) { SoundManager.PlayNetworkedAtPos(integrity.soundOnHit, gameObject.WorldPosServer(), Random.Range(0.9f, 1.1f)); } else if (isWeapon && weaponStats != null && weaponStats.hitSoundSettings == SoundItemSettings.OnlyObject && integrity.soundOnHit != "") { SoundManager.PlayNetworkedAtPos(integrity.soundOnHit, gameObject.WorldPosServer(), Random.Range(0.9f, 1.1f)); attackSoundName = ""; } integrity.ApplyDamage((int)damage, AttackType.Melee, damageType); didHit = true; } else { //damaging a living thing var rng = new System.Random(); // 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 (isWeapon || 90 >= rng.Next(1, 100)) { // The attack hit. victimHealth.ApplyDamageToBodypart(gameObject, (int)damage, AttackType.Melee, damageType, damageZone); didHit = true; } else { // The punch missed. string victimName = victim.Player()?.Name; SoundManager.PlayNetworkedAtPos("PunchMiss", transform.position); Chat.AddCombatMsgToChat(gameObject, $"You attempted to punch {victimName} but missed!", $"{gameObject.Player()?.Name} has attempted to punch {victimName}!"); } } } //common logic to do if we hit something if (didHit) { if (!string.IsNullOrEmpty(attackSoundName)) { SoundManager.PlayNetworkedAtPos(attackSoundName, transform.position); } if (damage > 0) { Chat.AddAttackMsgToChat(gameObject, victim, damageZone, weapon, attackedTile: attackedTile); } if (victim != gameObject) { RpcMeleeAttackLerp(attackDirection, weapon); //playerMove.allowInput = false; } } Cooldowns.TryStartServer(playerScript, CommonCooldowns.Instance.Melee); }
public void ServerPerformMeleeAttack(GameObject victim, Vector2 attackDirection, BodyPartType damageZone, LayerType layerType) { if (victim == null) { return; } if (Cooldowns.IsOnServer(playerScript, CommonCooldowns.Instance.Melee)) { return; } if (playerMove.allowInput == false) { return; } if (playerScript.IsGhost) { return; } if (playerScript.playerHealth.serverPlayerConscious == false) { return; } if (victim.TryGetComponent <InteractableTiles>(out var tiles)) { // validate based on position of target vector if (Validations.CanApply(playerScript, victim, NetworkSide.Server, targetVector: attackDirection) == false) { return; } } else { // validate based on position of target object if (Validations.CanApply(playerScript, victim, NetworkSide.Server) == false) { return; } } float damage = fistDamage; DamageType damageType = DamageType.Brute; AddressableAudioSource weaponSound = meleeSounds.PickRandom(); GameObject weapon = playerScript.playerNetworkActions.GetActiveHandItem(); ItemAttributesV2 weaponAttributes = weapon == null ? null : weapon.GetComponent <ItemAttributesV2>(); if (weaponAttributes != null) { damage = weaponAttributes.ServerHitDamage; damageType = weaponAttributes.ServerDamageType; weaponSound = weaponAttributes.hitSoundSettings == SoundItemSettings.OnlyObject ? null : weaponAttributes.ServerHitSound; slashChance = weaponAttributes.SlashChance; slashDamage = weaponAttributes.SlashDamage; pierceChance = weaponAttributes.PierceChance; pierceDamage = weaponAttributes.PierceDamage; burnDamage = weaponAttributes.BurnDamage; } LayerTile attackedTile = null; bool didHit = false; // If Tilemap LayerType is not None then it is a tilemap being attacked if (layerType != LayerType.None) { var tileChangeManager = victim.GetComponent <TileChangeManager>(); if (tileChangeManager == null) { return; // Make sure its on a matrix that is destructable } // Tilemap stuff: var tileMapDamage = victim.GetComponentInChildren <MetaTileMap>().Layers[layerType].gameObject.GetComponent <TilemapDamage>(); if (tileMapDamage == null) { return; } var worldPos = (Vector2)transform.position + attackDirection; attackedTile = tileChangeManager.InteractableTiles.LayerTileAt(worldPos, true); // Tile itself is responsible for playing victim damage sound tileMapDamage.ApplyDamage(damage, AttackType.Melee, worldPos); didHit = true; } // Damaging an object else if (victim.TryGetComponent <Integrity>(out var integrity) && victim.TryGetComponent <Meleeable>(out var meleeable) && meleeable.IsMeleeable) { if (weaponAttributes != null && weaponAttributes.hitSoundSettings != SoundItemSettings.OnlyItem) { AudioSourceParameters audioSourceParameters = new AudioSourceParameters(pitch: Random.Range(0.9f, 1.1f)); SoundManager.PlayNetworkedAtPos(integrity.soundOnHit, gameObject.WorldPosServer(), audioSourceParameters, sourceObj: gameObject); } integrity.ApplyDamage(damage, AttackType.Melee, damageType); didHit = true; }