Example #1
0
        public bool WillInteract(HandApply interaction, NetworkSide side)
        {
            // standard validation for interaction and harm intent
            if (!DefaultWillInteract.Default(interaction, side))
            {
                return(false);
            }

            ItemAttributesV2 attr = interaction.TargetObject.GetComponent <ItemAttributesV2>();

            return(attr.HasTrait(LightableSurface) && interaction.Intent == Intent.Harm);
        }
Example #2
0
        public void RefreshParts(IDictionary <GameObject, int> partsInFrame)
        {
            // Get the machine stock parts used in this instance and get the tier of each part.
            // Collection is unorganized so run through the whole list.
            foreach (GameObject part in partsInFrame.Keys)
            {
                ItemAttributesV2 partAttributes = part.GetComponent <ItemAttributesV2>();
                if (partAttributes.HasTrait(MachinePartsItemTraits.Instance.MicroLaser))
                {
                    laserTier = part.GetComponent <StockTier>().Tier;
                }

                if (partAttributes.HasTrait(MachinePartsItemTraits.Instance.MatterBin))
                {
                    int binTier = part.GetComponent <StockTier>().Tier;

                    // Decide ItemStorageStructure based on tier. Currently: slot size == twice the bin tier.
                    storage.AcceptNewStructure(TierStorage[binTier - 1]);
                }
            }
        }
Example #3
0
 public void RefreshParts(IDictionary <GameObject, int> partsInFrame)
 {
     // Get the machine stock parts used in this instance and get the tier of each part.
     // Collection is unorganized so run through the whole list.
     foreach (GameObject part in partsInFrame.Keys)
     {
         ItemAttributesV2 partAttributes = part.GetComponent <ItemAttributesV2>();
         if (partAttributes.HasTrait(MachinePartsItemTraits.Instance.MicroLaser))
         {
             laserTier = part.GetComponent <StockTier>().Tier;
         }
     }
 }
    public void CmdRequestMeleeAttack(GameObject victim, Vector2 attackDirection,
                                      BodyPartType damageZone, LayerType layerType)
    {
        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;
        }

        if (!allowAttack)
        {
            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;


        // 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)
            {
                var worldPos = (Vector2)transform.position + attackDirection;
                attackedTile = tileChangeManager.InteractableTiles.LayerTileAt(worldPos);
                tileMapDamage.DoMeleeDamage(worldPos,
                                            gameObject, (int)damage);
                didHit = true;
            }
        }
        else
        {
            //a regular object being attacked

            //butchering
            //TODO: Move butchering logic to IF2, it should be a progress action done on corpses (make a Corpse component probably)
            LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>();
            if (victimHealth != null && victimHealth.IsDead && isWeapon && weaponAttr.HasTrait(KnifeTrait))
            {
                if (victim.GetComponent <SimpleAnimal>())
                {
                    SimpleAnimal attackTarget = victim.GetComponent <SimpleAnimal>();
                    RpcMeleeAttackLerp(attackDirection, weapon);
                    playerMove.allowInput = false;
                    attackTarget.Harvest();
                    SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
                }
                else
                {
                    PlayerHealth attackTarget = victim.GetComponent <PlayerHealth>();
                    RpcMeleeAttackLerp(attackDirection, weapon);
                    playerMove.allowInput = false;
                    attackTarget.Harvest();
                    SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
                }
            }

            var integrity = victim.GetComponent <Integrity>();
            if (integrity != null)
            {
                //damaging an object
                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)
        {
            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;
            }
        }

        //no matter what, start a cooldown for attacking again so they can't spam attack requests
        StartCoroutine(AttackCoolDown());
    }