/// <summary> /// Sends a player message to the server. /// The message is omitted if too many messages have been sent recently. /// The message is shortened if the player has send too many characters recently. /// In either case the player will see a warning in their chat log. /// </summary> /// <param name="message">The player's message.</param> /// <param name="selectedChannels">The selected channels, which are simply passed along.</param> public void Send(string message, ChatChannel selectedChannels) { DecayFiltersOverTime(); // Decrease cpm and messages since last having spoken // Limit number of messages if (numMessages + 1 > numMessageMax || cpm + 1 > cpmMax) { if (selectedChannels.HasFlag(ChatChannel.OOC) || selectedChannels.HasFlag(ChatChannel.Ghost)) { Chat.AddExamineMsgToClient(numMessagesWarningOOC); } else { Chat.AddExamineMsgToClient(numMessagesWarning); } return; } // Users message will (at least partiall) be spoken, so count it. numMessages++; cpm += message.Length; // Limit characters per minute int numCharsOverLimit = 0; if (cpm > cpmMax) { // Too many characters, calculate how many need to be removed. float cpmOver = cpm - cpmMax; cpm = cpmMax; // Characters will be removed, so cpm must be lowered again. numCharsOverLimit = (int)Math.Floor(cpmOver); message = message.Remove(message.Length - numCharsOverLimit) + "..."; } // Don't send message if it got shortened below the limit. if (0 < numCharsOverLimit && numCharsOverLimit < cpmMinCharacters) { return; } // Send message, which might have been shortened because of the character limit per minute. PostToChatMessage.Send(message, selectedChannels); // Notify player that their message got cut short. if (numCharsOverLimit > 0) { if (selectedChannels.HasFlag(ChatChannel.OOC) || selectedChannels.HasFlag(ChatChannel.Ghost)) { Chat.AddExamineMsgToClient(cpmWarningOOC); } else { Chat.AddExamineMsgToClient(cpmWarning); } } }
public void VendItem(VendorItem item) { VendorItem itemToSpawn = null; foreach (var vendorItem in vendorContent) { if (vendorItem == item) { itemToSpawn = item; break; } } if (!CanSell(itemToSpawn)) { return; } Vector3 spawnPos = vendor.gameObject.RegisterTile().WorldPositionServer; var spawnedItem = PoolManager.PoolNetworkInstantiate(itemToSpawn.Item, spawnPos, vendor.transform.parent); itemToSpawn.Stock--; PostToChatMessage.Send("Item given", ChatChannel.Examine); //Ejecting in direction if (vendor.EjectObjects && vendor.EjectDirection != EjectDirection.None) { Vector3 offset = Vector3.zero; switch (vendor.EjectDirection) { case EjectDirection.Up: offset = vendor.transform.rotation * Vector3.up / Random.Range(4, 12); break; case EjectDirection.Down: offset = vendor.transform.rotation * Vector3.down / Random.Range(4, 12); break; case EjectDirection.Random: offset = new Vector3(Random.Range(-0.15f, 0.15f), Random.Range(-0.15f, 0.15f), 0); break; } spawnedItem.GetComponent <CustomNetTransform>()?.Throw(new ThrowInfo { ThrownBy = gameObject, Aim = BodyPartType.Chest, OriginPos = spawnPos, TargetPos = spawnPos + offset, SpinMode = (vendor.EjectDirection == EjectDirection.Random) ? SpinMode.Clockwise : SpinMode.None }); } SendToChat(vendMessage); UpdateList(); allowSell = false; StartCoroutine(VendorInputCoolDown()); }
private void PlayerSendChat() { PostToChatMessage.Send(InputFieldChat.text, PlayerManager.LocalPlayerScript.SelectedChannels); if (InputFieldChat.text != "") { PlayerManager.LocalPlayerScript.playerNetworkActions.CmdToggleChatIcon(true); } InputFieldChat.text = ""; }
//We want ChatEvent to be created on the server, so we're only passing the individual variables public static PostToChatMessage Send(string message, ChatChannel channels) { PostToChatMessage msg = new PostToChatMessage { Channels = channels, ChatMessageText = message }; msg.Send(); return msg; }
public void ReportKills() { if (syndicateKills != 0) { PostToChatMessage.Send("Syndicate managed to kill " + syndicateKills + " crew members.", ChatChannel.System); } if (crewKills != 0) { PostToChatMessage.Send("Crew managed to kill " + crewKills + " Syndicate operators.", ChatChannel.System); } }
private void PlayerSendChat() { // Selected channels already masks all unavailable channels in it's get method PostToChatMessage.Send(InputFieldChat.text, SelectedChannels); if (PlayerChatShown()) { PlayerManager.LocalPlayerScript.playerNetworkActions.CmdToggleChatIcon(true, InputFieldChat.text, SelectedChannels); } InputFieldChat.text = ""; }
public static void Kick(ConnectedPlayer player, string raisins = "4 no raisins") { if (!player.Connection.isConnected) { Logger.Log($"Not kicking, already disconnected: {player}", Category.Connections); return; } Logger.Log($"Kicking {player} : {raisins}", Category.Connections); InfoWindowMessage.Send(player.GameObject, $"Kicked: {raisins}", "Kicked"); PostToChatMessage.Send($"Player '{player.Name}' got kicked: {raisins}", ChatChannel.System); player.Connection.Disconnect(); player.Connection.Dispose(); }
/// <summary> /// Called after MatrixManager is initialized /// </summary> private void InitEscapeStuff() { //Primary escape shuttle lookup if (!PrimaryEscapeShuttle) { var shuttles = FindObjectsOfType <EscapeShuttle>(); if (shuttles.Length != 1) { Logger.LogError("Primary escape shuttle is missing from GameManager!", Category.Round); return; } Logger.LogWarning("Primary escape shuttle is missing from GameManager, but one was found on scene"); primaryEscapeShuttle = shuttles[0]; } //later, maybe: keep a list of all computers and call the shuttle automatically with a 25 min timer if they are deleted //Starting up at Centcom coordinates PrimaryEscapeShuttle.MatrixInfo.MatrixMove.SetPosition(PrimaryEscapeShuttle.CentcomDest.Position); bool beenToStation = false; PrimaryEscapeShuttle.OnShuttleUpdate?.AddListener(status => { //status display ETA tracking if (status == ShuttleStatus.OnRouteStation) { PrimaryEscapeShuttle.OnTimerUpdate.AddListener(TrackETA); } else { PrimaryEscapeShuttle.OnTimerUpdate.RemoveListener(TrackETA); CentComm.OnStatusDisplayUpdate.Invoke(StatusDisplayChannel.EscapeShuttle, string.Empty); } if (status == ShuttleStatus.DockedCentcom && beenToStation) { RoundEnd(); Logger.Log("Shuttle arrived to Centcom, Round should end here", Category.Round); } if (status == ShuttleStatus.DockedStation) { beenToStation = true; SoundManager.PlayNetworked("Disembark"); PostToChatMessage.Send("Escape shuttle has arrived! Crew has 1 minute to get on it.", ChatChannel.System); //should be changed to manual send later StartCoroutine(SendEscapeShuttle(60)); } }); }
protected override void OnDeathActions() { if (CustomNetworkManager.Instance._isServer) { PlayerNetworkActions pna = gameObject.GetComponent <PlayerNetworkActions>(); PlayerMove pm = gameObject.GetComponent <PlayerMove>(); ConnectedPlayer player = PlayerList.Instance.Get(gameObject); string killerName = "Stressful work"; if (LastDamagedBy != null) { killerName = PlayerList.Instance.Get(LastDamagedBy).Name; } string playerName = player.Name ?? "dummy"; if (killerName == playerName) { PostToChatMessage.Send(playerName + " commited suicide", ChatChannel.System); //Killfeed } else if (killerName.EndsWith(playerName)) { // chain reactions PostToChatMessage.Send( playerName + " screwed himself up with some help (" + killerName + ")", ChatChannel.System); //Killfeed } else { PlayerList.Instance.UpdateKillScore(LastDamagedBy, gameObject); } pna.DropItem("rightHand"); pna.DropItem("leftHand"); if (isServer) { EffectsFactory.Instance.BloodSplat(transform.position, BloodSplatSize.large); } PlayerDeathMessage.Send(gameObject); //syncvars for everyone pm.isGhost = true; pm.allowInput = true; //consider moving into PlayerDeathMessage.Process() pna.RpcSpawnGhost(); RpcPassBullets(gameObject); //FIXME Remove for next demo pna.RespawnPlayer(10); } }
private bool ValidateFloating(Vector3 origin, Vector3 goal) { // Logger.Log( $"{gameObject.name} check {origin}->{goal}. Speed={serverState.Speed}" ); Vector3Int intOrigin = Vector3Int.RoundToInt(origin); Vector3Int intGoal = Vector3Int.RoundToInt(goal); var info = serverState.ActiveThrow; List <HealthBehaviour> hitDamageables; if (CanDriftTo(intOrigin, intGoal) & !HittingSomething(intGoal, info.ThrownBy, out hitDamageables)) { //if object is solid, check if player is nearby to make it stop return(registerTile.IsPassable() ? true : !IsPlayerNearby(serverState)); } else { //Can't drift to goal for some reason: //Check Tile damage from throw var hit2D = Physics2D.RaycastAll(origin, info.Trajectory.normalized, 1.5f, tileDmgMask); for (int i = 0; i < hit2D.Length; i++) { //Debug.Log("THROW HIT: " + hit2D[i].collider.gameObject.name); //TilemapDamage automatically detects if a layer is below another damageable layer and won't affect it var tileDmg = hit2D[i].collider.gameObject.GetComponent <TilemapDamage>(); if (tileDmg != null) { var damage = ( int )(ItemAttributes.throwDamage * 2); tileDmg.DoThrowDamage(intGoal, info, damage); } } } //Hurting what we can if (hitDamageables != null && hitDamageables.Count > 0 && !Equals(info, ThrowInfo.NoThrow)) { for (var i = 0; i < hitDamageables.Count; i++) { //Remove cast to int when moving health values to float var damage = ( int )(ItemAttributes.throwDamage * 2); hitDamageables[i].ApplyDamage(info.ThrownBy, damage, DamageType.BRUTE, info.Aim); PostToChatMessage.SendThrowHitMessage(gameObject, hitDamageables[i].gameObject, damage, info.Aim); } //hit sound PlaySoundMessage.SendToAll("GenericHit", transform.position, 1f); } return(false); }
private void Update() { if (!isProcessingSpaceBody && PendingSpaceBodies.Count > 0) { isProcessingSpaceBody = true; StartCoroutine(ProcessSpaceBody(PendingSpaceBodies.Dequeue())); } if (waitForRestart) { restartTime -= Time.deltaTime; if (restartTime <= 0f) { waitForRestart = false; RestartRound(); } } else if (counting) { GetRoundTime -= Time.deltaTime; roundTimer.text = Mathf.Floor(GetRoundTime / 60).ToString("00") + ":" + (GetRoundTime % 60).ToString("00"); if (GetRoundTime <= 0f) { counting = false; roundTimer.text = "GameOver"; // Prevents annoying sound duplicate when testing if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null && !GameData.Instance.testServer) { SoundManager.Play("ApcDestroyed", 0.3f, 1f, 0f); } if (CustomNetworkManager.Instance._isServer) { waitForRestart = true; PlayerList.Instance.ReportScores(); } } //Nuke ops shuttle arrival if (shuttleArrived == true && shuttleArrivalBroadcasted == false) { PostToChatMessage.Send("Escape shuttle has arrived! Crew has 1 minute to get on it.", ChatChannel.System); shuttleArrivalBroadcasted = true; } } }
public void ReportScores() { //TODO: Add server announcement messages /* * var scoreSort = playerScores.OrderByDescending(pair => pair.Value) * .ToDictionary(pair => pair.Key, pair => pair.Value); * * foreach (KeyValuePair<string, int> ps in scoreSort) * { * UIManager.Chat.ReportToChannel("<b>" + ps.Key + "</b> total kills: <b>" + ps.Value + "</b>"); * } */ PostToChatMessage.Send("Game Restarting in 10 seconds...", ChatChannel.System); }
public void ReportScores() { if (!reportDone) { //if (!nukeSetOff && syndicateKills == 0 && crewKills == 0) //{ // PostToChatMessage.Send("Nobody killed anybody. F*****g hippies.", ChatChannel.System); //} if (nukeSetOff) { PostToChatMessage.Send("Nuke has been detonated, <b>Syndicate wins.</b>", ChatChannel.System); ReportKills(); } else { int alivePlayers = GetAlivePlayers().Count; int crewCountOnboard = GetAliveShuttleCrew().Count; if (alivePlayers > 0 && crewCountOnboard == 0) { PostToChatMessage.Send("Station crew failed to escape, <b>Syndicate wins.</b>", ChatChannel.System); ReportKills(); } else if (alivePlayers == 0) { PostToChatMessage.Send("All crew members are dead, <b>Syndicate wins.</b>", ChatChannel.System); ReportKills(); } else if (alivePlayers > 0 && crewCountOnboard > 0) { PostToChatMessage.Send(crewCountOnboard + " Crew member(s) have managed to escape the station. <b>Syndicate lost.</b>", ChatChannel.System); ReportKills(); } } PostToChatMessage.Send("Game Restarting in 30 seconds...", ChatChannel.System); reportDone = true; } List <ConnectedPlayer> GetAliveShuttleCrew() { var playersOnMatrix = GetPlayersOnMatrix(GameManager.Instance.PrimaryEscapeShuttle.MatrixInfo); return(GetAlivePlayers(playersOnMatrix).FindAll(p => p.Job != JobType.SYNDICATE)); } }
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(); }
protected override void OnDeathActions() { if (CustomNetworkManager.Instance._isServer) { PlayerNetworkActions pna = gameObject.GetComponent <PlayerNetworkActions>(); PlayerMove pm = gameObject.GetComponent <PlayerMove>(); ConnectedPlayer player = PlayerList.Instance.Get(gameObject); string killerName = "Stressful work"; if (LastDamagedBy != null) { killerName = PlayerList.Instance.Get(LastDamagedBy).Name; } string playerName = player.Name ?? "dummy"; if (killerName == playerName) { PostToChatMessage.Send(playerName + " commited suicide", ChatChannel.System); //Killfeed } else if (killerName.EndsWith(playerName)) { // chain reactions PostToChatMessage.Send( playerName + " screwed himself up with some help (" + killerName + ")", ChatChannel.System); //Killfeed } else { PlayerList.Instance.UpdateKillScore(LastDamagedBy, gameObject); } pna.DropItem(EquipSlot.rightHand); pna.DropItem(EquipSlot.leftHand); if (isServer) { EffectsFactory.Instance.BloodSplat(transform.position, BloodSplatSize.large); } PlayerDeathMessage.Send(gameObject); } }
protected override void OnDeathActions() { if (CustomNetworkManager.Instance._isServer) { if (LastDamagedBy == gameObject.name) { PostToChatMessage.Send(gameObject.name + " commited suicide", ChatChannel.System); //Killfeed } else if (LastDamagedBy.EndsWith(gameObject.name)) { // chain reactions PostToChatMessage.Send( gameObject.name + " screwed himself up with some help (" + LastDamagedBy + ")", ChatChannel.System); //Killfeed } else { PlayerList.Instance.UpdateKillScore(LastDamagedBy); PostToChatMessage.Send(LastDamagedBy + " has killed " + gameObject.name, ChatChannel.System); //Killfeed } playerNetworkActions.ValidateDropItem("rightHand", true); playerNetworkActions.ValidateDropItem("leftHand", true); if (isServer) { EffectsFactory.Instance.BloodSplat(transform.position, BloodSplatSize.large); } playerNetworkActions.RpcSpawnGhost(); playerMove.isGhost = true; playerMove.allowInput = true; //FIXME Remove for next demo playerNetworkActions.RespawnPlayer(10); } }
private void PlayerSendChat(string sendMessage) { // Selected channels already masks all unavailable channels in it's get method PostToChatMessage.Send(sendMessage, SelectedChannels); InputFieldChat.text = ""; }
protected override void OnDeathActions() { if (CustomNetworkManager.Instance._isServer) { PlayerNetworkActions pna = gameObject.GetComponent <PlayerNetworkActions>(); PlayerMove pm = gameObject.GetComponent <PlayerMove>(); ConnectedPlayer player = PlayerList.Instance.Get(gameObject); string killerName = "stressfull work"; if (LastDamagedBy != null) { killerName = PlayerList.Instance.Get(LastDamagedBy).Name; } if (killerName == player.Name) { PostToChatMessage.Send(player.Name + " commited suicide", ChatChannel.System); //Killfeed } else if (killerName.EndsWith(player.Name)) { // chain reactions PostToChatMessage.Send( player.Name + " screwed himself up with some help (" + killerName + ")", ChatChannel.System); //Killfeed } else { PlayerList.Instance.UpdateKillScore(LastDamagedBy, gameObject); string departmentKillText = ""; if (LastDamagedBy != null) { JobDepartment killerDepartment = SpawnPoint.GetJobDepartment(LastDamagedBy.GetComponent <PlayerScript>().JobType); JobDepartment victimDepartment = SpawnPoint.GetJobDepartment(gameObject.GetComponent <PlayerScript>().JobType); if (killerDepartment == victimDepartment) { departmentKillText = ", losing " + killerDepartment.GetDescription() + " 1 point for team killing!"; } else { departmentKillText = ", 1 point to " + killerDepartment.GetDescription() + "!"; } } //TDM demo killfeed PostToChatMessage.Send(killerName + " has killed " + player.Name + departmentKillText, ChatChannel.System); //Combat demo killfeed //PostToChatMessage.Send(killerName + " has killed " + gameObject.name, ChatChannel.System); } pna.ValidateDropItem("rightHand", true, transform.position); pna.ValidateDropItem("leftHand", true, transform.position); if (isServer) { EffectsFactory.Instance.BloodSplat(transform.position, BloodSplatSize.large); } pna.RpcSpawnGhost(); pm.isGhost = true; pm.allowInput = true; RpcPassBullets(gameObject); PlayerDeathMessage.Send(gameObject); //FIXME Remove for next demo pna.RespawnPlayer(10); } }
public void CmdRequestMeleeAttack(GameObject victim, string slot, Vector2 stabDirection, BodyPartType damageZone) { if (!playerMove.allowInput || playerMove.isGhost || !victim || !playerScript.playerNetworkActions.SlotNotEmpty(slot) || !PlayerManager.PlayerInReach(victim.transform) ) { return; } var weapon = playerScript.playerNetworkActions.Inventory[slot]; ItemAttributes weaponAttr = weapon.GetComponent <ItemAttributes>(); HealthBehaviour victimHealth = victim.GetComponent <HealthBehaviour>(); // checks object and component existence before defining healthBehaviour variable. if (victimHealth.IsDead == false) { if (!allowAttack) { return; } if (victim != gameObject) { RpcMeleeAttackLerp(stabDirection, weapon); } victimHealth.ApplyDamage(gameObject, ( int )weaponAttr.hitDamage, DamageType.BRUTE, damageZone); if (weaponAttr.hitDamage > 0) { PostToChatMessage.SendItemAttackMessage(weapon, gameObject, victim, (int)weaponAttr.hitDamage, damageZone); } soundNetworkActions.RpcPlayNetworkSound(weaponAttr.hitSound, transform.position); StartCoroutine(AttackCoolDown()); } else { //Butchering if we can if (weaponAttr.type != ItemType.Knife) { return; } if (victim.GetComponent <SimpleAnimal>()) { SimpleAnimal attackTarget = victim.GetComponent <SimpleAnimal>(); RpcMeleeAttackLerp(stabDirection, weapon); attackTarget.Harvest(); soundNetworkActions.RpcPlayNetworkSound("BladeSlice", transform.position); } else { PlayerHealth attackTarget = victim.GetComponent <PlayerHealth>(); RpcMeleeAttackLerp(stabDirection, weapon); attackTarget.Harvest(); soundNetworkActions.RpcPlayNetworkSound("BladeSlice", transform.position); } } }
public void CmdRequestMeleeAttack(GameObject victim, string slot, Vector2 stabDirection, BodyPartType damageZone, LayerType layerType) { if (!playerMove.allowInput || playerMove.isGhost || !victim || !playerScript.playerNetworkActions.SlotNotEmpty(slot) || !playerScript.playerHealth.serverPlayerConscious ) { return; } if (!allowAttack) { return; } var weapon = playerScript.playerNetworkActions.Inventory[slot].Item; 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)) { return; } //Meaty bodies: LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>(); if (victimHealth.IsDead && weaponAttr.type == 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); } return; } if (victim != gameObject) { RpcMeleeAttackLerp(stabDirection, weapon); playerMove.allowInput = false; } victimHealth.ApplyDamage(gameObject, (int)weaponAttr.hitDamage, DamageType.Brute, damageZone); if (weaponAttr.hitDamage > 0) { PostToChatMessage.SendItemAttackMessage(weapon, gameObject, victim, (int)weaponAttr.hitDamage, damageZone); } SoundManager.PlayNetworkedAtPos(weaponAttr.hitSound, transform.position); StartCoroutine(AttackCoolDown()); }