816 lines
39 KiB
C#
816 lines
39 KiB
C#
using System.Collections.Generic;
|
|
|
|
public class ItemActionAttackRebirth
|
|
{
|
|
static float _KillExpMaxDist = 50f;
|
|
static float _NPCKillExpMod = 1f;
|
|
|
|
public static void Hit(
|
|
WorldRayHitInfo hitInfo_,
|
|
int attackerEntityId_,
|
|
EnumDamageTypes damageType_,
|
|
float blockDamage_,
|
|
float entityDamage_,
|
|
float staminaDamageMultiplier_,
|
|
float weaponCondition_,
|
|
float criticalHitChanceOLD_, // unused
|
|
float dismemberChance_,
|
|
string attackingDeviceMadeOf_,
|
|
DamageMultiplier damageMultiplier_,
|
|
List<string> buffActions_,
|
|
ItemActionAttack.AttackHitInfo attackDetails_,
|
|
int flags_ = 1,
|
|
int actionExp_ = 0, // unused
|
|
float actionExpBonus_ = 0f, // unused
|
|
ItemActionAttack rangeCheckedAction_ = null,
|
|
Dictionary<string, ItemActionAttack.Bonuses> toolBonuses_ = null,
|
|
ItemActionAttack.EnumAttackMode attackMode_ = ItemActionAttack.EnumAttackMode.RealNoHarvesting,
|
|
Dictionary<string, string> hitSoundOverrides_ = null,
|
|
int ownedEntityId_ = -1,
|
|
ItemValue damagingItemValue_ = null)
|
|
{
|
|
//Log.Out("ItemActionAttackPatches-Hit attackerEntityId_: " + attackerEntityId_);
|
|
//Log.Out("ItemActionAttackPatches-Hit ownedEntityId_: " + ownedEntityId_);
|
|
//Log.Out("ItemActionAttackPatches-Hit attackDetails_.WeaponTypeTag: " + attackDetails_.WeaponTypeTag);
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit weaponCondition_: " + weaponCondition_);
|
|
//Log.Out("ItemActionAttackPatches-Hit blockDamage_: " + blockDamage_);
|
|
//Log.Out("ItemActionAttackPatches-Hit entityDamage_: " + entityDamage_);
|
|
|
|
if (hitInfo_ == null || hitInfo_.tag == null) return;
|
|
|
|
bool bypassXP = false;
|
|
|
|
if (damagingItemValue_ != null && damagingItemValue_.ItemClass != null)
|
|
{
|
|
if (damagingItemValue_.ItemClass.Name.ToLower() == "autoturret" ||
|
|
damagingItemValue_.ItemClass.Name.ToLower() == "shotgunturret"
|
|
)
|
|
{
|
|
bypassXP = true;
|
|
}
|
|
}
|
|
|
|
World world = GameManager.Instance.World;
|
|
bool isNot_RNHOE = true;
|
|
|
|
if (attackMode_ == ItemActionAttack.EnumAttackMode.RealNoHarvestingOrEffects)
|
|
{
|
|
isNot_RNHOE = false;
|
|
attackMode_ = ItemActionAttack.EnumAttackMode.RealNoHarvesting;
|
|
}
|
|
|
|
if (attackDetails_ != null)
|
|
{
|
|
attackDetails_.itemsToDrop = null;
|
|
attackDetails_.bBlockHit = false;
|
|
attackDetails_.entityHit = null;
|
|
}
|
|
|
|
string particleCategory = null;
|
|
string surfaceCategory = null;
|
|
float lightValue = 1f;
|
|
Color particleColor = Color.white;
|
|
bool islphModLessThanOne = false;
|
|
EntityAlive attackingEntity = world.GetEntity(attackerEntityId_) as EntityAlive;
|
|
EntityNPCRebirth attackingNPC = attackingEntity as EntityNPCRebirth;
|
|
bool isInventoryItem = false;
|
|
|
|
if (attackingEntity != null)
|
|
{
|
|
if (damagingItemValue_ == null)
|
|
{
|
|
damagingItemValue_ = attackingEntity.inventory.holdingItemItemValue;
|
|
}
|
|
|
|
isInventoryItem = damagingItemValue_.Equals(attackingEntity.inventory.holdingItemItemValue);
|
|
}
|
|
|
|
bool isNotPlayerHit = true;
|
|
|
|
#region Hit -> Block/Terrain
|
|
if (GameUtils.IsBlockOrTerrain(hitInfo_.tag))
|
|
{
|
|
// Does this work outside of Unity Editor mode?
|
|
/*if (ItemAction.ShowDebugDisplayHit)
|
|
{
|
|
Vector3 position = Camera.main.transform.position;
|
|
DebugLines.Create(null, attackingEntity.RootTransform, position + Origin.position, hitInfo_.hit.pos, new Color(1f, 0.5f, 1f), new Color(1f, 0f, 1f), ItemAction.DebugDisplayHitSize * 2f, ItemAction.DebugDisplayHitSize, ItemAction.DebugDisplayHitTime);
|
|
}*/
|
|
|
|
// Nullify npc hire damage. Would be better to stop them from actually shooting/swinging in the first place
|
|
if (attackingNPC != null && attackingNPC.Buffs.GetCustomVar("$Leader") > 0 && attackDetails_.damage == 0)
|
|
{
|
|
//Log.Out("ItemActionAttackPatches-Hit 7a, _attackDetails: " + _attackDetails.damage);
|
|
return;
|
|
}
|
|
|
|
ChunkCluster chunkCluster = world.ChunkClusters[hitInfo_.hit.clrIdx];
|
|
|
|
if (chunkCluster == null) return;
|
|
|
|
Vector3i vecHitBlockPos = hitInfo_.hit.blockPos;
|
|
BlockValue blockValue = chunkCluster.GetBlock(vecHitBlockPos);
|
|
|
|
if (blockValue.isair && hitInfo_.hit.blockValue.Block.IsDistantDecoration && hitInfo_.hit.blockValue.damage >= hitInfo_.hit.blockValue.Block.MaxDamage - 1)
|
|
{
|
|
blockValue = hitInfo_.hit.blockValue;
|
|
world.SetBlockRPC(vecHitBlockPos, blockValue);
|
|
}
|
|
|
|
Block blockClass = blockValue.Block;
|
|
|
|
if (blockClass == null) return;
|
|
|
|
if (blockValue.ischild)
|
|
{
|
|
vecHitBlockPos = blockClass.multiBlockPos.GetParentPos(vecHitBlockPos, blockValue);
|
|
blockValue = chunkCluster.GetBlock(vecHitBlockPos);
|
|
blockClass = blockValue.Block;
|
|
|
|
if (blockClass == null) return;
|
|
}
|
|
|
|
if (blockValue.isair) return;
|
|
|
|
float lphModifier = world.GetLandProtectionHardnessModifier(hitInfo_.hit.blockPos, attackingEntity, world.GetGameManager().GetPersistentLocalPlayer());
|
|
if (world.IsWithinTraderArea(hitInfo_.hit.blockPos))
|
|
{
|
|
lphModifier = 0f;
|
|
}
|
|
|
|
if (blockClass.blockMaterial.id == "Mbedrock")
|
|
{
|
|
lphModifier = 0f;
|
|
}
|
|
|
|
if (lphModifier != 1f)
|
|
{
|
|
if (attackingEntity != null && attackMode_ != ItemActionAttack.EnumAttackMode.Simulate && attackingEntity is EntityPlayer && !damagingItemValue_.ItemClass.ignoreKeystoneSound && !damagingItemValue_.ToBlockValue().Block.IgnoreKeystoneOverlay)
|
|
{
|
|
attackingEntity.PlayOneShot("keystone_impact_overlay");
|
|
}
|
|
|
|
if (lphModifier < 1f)
|
|
{
|
|
islphModLessThanOne = true;
|
|
}
|
|
}
|
|
|
|
if (vecHitBlockPos != attackDetails_.hitPosition || lphModifier != attackDetails_.hardnessScale || blockValue.type != attackDetails_.blockBeingDamaged.type || (isInventoryItem && damagingItemValue_.SelectedAmmoTypeIndex != attackDetails_.ammoIndex))
|
|
{
|
|
float hardness = Mathf.Max(blockClass.GetHardness(), 0.1f) * lphModifier;
|
|
float dmgPerHit = blockDamage_ * (damageMultiplier_ != null ? damageMultiplier_.Get(blockClass.blockMaterial.DamageCategory) : 1f);
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit BEFORE dmgPerHit: " + dmgPerHit);
|
|
|
|
if (attackingEntity != null)
|
|
{
|
|
dmgPerHit *= attackingEntity.GetBlockDamageScale();
|
|
}
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit MID dmgPerHit: " + dmgPerHit);
|
|
|
|
if (toolBonuses_ != null && toolBonuses_.Count > 0)
|
|
{
|
|
dmgPerHit *= CalculateHarvestToolDamageBonus(toolBonuses_, blockClass.itemsToDrop);
|
|
attackDetails_.bHarvestTool = true;
|
|
}
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit AFTER dmgPerHit: " + dmgPerHit);
|
|
//Log.Out("ItemActionAttackPatches-Hit hardness: " + hardness);
|
|
//Log.Out("ItemActionAttackPatches-Hit (dmgPerHit / hardness): " + (dmgPerHit / hardness));
|
|
|
|
attackDetails_.damagePerHit = (!islphModLessThanOne) ? (dmgPerHit / hardness) : 0f;
|
|
attackDetails_.damage = 0f;
|
|
attackDetails_.hardnessScale = lphModifier;
|
|
attackDetails_.hitPosition = vecHitBlockPos;
|
|
attackDetails_.blockBeingDamaged = blockValue;
|
|
|
|
if (isInventoryItem)
|
|
{
|
|
attackDetails_.ammoIndex = damagingItemValue_.SelectedAmmoTypeIndex;
|
|
}
|
|
}
|
|
|
|
attackDetails_.raycastHitPosition = hitInfo_.hit.blockPos;
|
|
Block block2 = hitInfo_.fmcHit.blockValue.Block;
|
|
lightValue = world.GetLightBrightness(hitInfo_.fmcHit.blockPos);
|
|
particleColor = block2.GetColorForSide(hitInfo_.fmcHit.blockValue, hitInfo_.fmcHit.blockFace);
|
|
particleCategory = block2.GetParticleForSide(hitInfo_.fmcHit.blockValue, hitInfo_.fmcHit.blockFace);
|
|
MaterialBlock materialForSide = block2.GetMaterialForSide(hitInfo_.fmcHit.blockValue, hitInfo_.fmcHit.blockFace);
|
|
surfaceCategory = materialForSide.SurfaceCategory;
|
|
|
|
//NEW CODE - START
|
|
if (attackingEntity is EntityNPCRebirth)
|
|
{
|
|
staminaDamageMultiplier_ = 1;
|
|
}
|
|
//NEW CODE - END
|
|
|
|
float dmgPerHitStam = attackDetails_.damagePerHit * staminaDamageMultiplier_;
|
|
//Log.Out($"dmgPerHitStam: {dmgPerHitStam}, damagePerHit: {attackDetails_.damagePerHit}, staminaDamageMultiplier_: {staminaDamageMultiplier_}");
|
|
|
|
if (attackingEntity != null)
|
|
{
|
|
string dmgCategory = materialForSide.DamageCategory ?? string.Empty;
|
|
dmgPerHitStam = (int)EffectManager.GetValue(PassiveEffects.DamageModifier, damagingItemValue_, dmgPerHitStam, attackingEntity, null, FastTags<TagGroup.Global>.Parse(dmgCategory) | attackDetails_.WeaponTypeTag | hitInfo_.fmcHit.blockValue.Block.Tags);
|
|
}
|
|
|
|
dmgPerHitStam = ItemActionAttack.DegradationModifier(dmgPerHitStam, weaponCondition_);
|
|
dmgPerHitStam = (!islphModLessThanOne) ? Utils.FastMax(1f, dmgPerHitStam) : 0f;
|
|
|
|
attackDetails_.damage += dmgPerHitStam;
|
|
attackDetails_.bKilled = false;
|
|
attackDetails_.damageTotalOfTarget = blockValue.damage + attackDetails_.damage;
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit blockValue.damage: " + blockValue.damage);
|
|
//Log.Out("ItemActionAttackPatches-Hit attackDetails_.damage: " + attackDetails_.damage);
|
|
|
|
if (attackDetails_.damage > 0f)
|
|
{
|
|
Vector3 _hitFaceCenter;
|
|
Vector3 _hitFaceNormal;
|
|
BlockFace blockFaceFromHitInfo = GameUtils.GetBlockFaceFromHitInfo(vecHitBlockPos, blockValue, hitInfo_.hitCollider, hitInfo_.hitTriangleIdx, out _hitFaceCenter, out _hitFaceNormal);
|
|
int blockFaceTexture = chunkCluster.GetBlockFaceTexture(vecHitBlockPos, blockFaceFromHitInfo);
|
|
int curBlockDmg = blockValue.damage; // the amount of damage this block has currently taken. 0 if block hp is 100%
|
|
bool isOverkill = curBlockDmg >= blockClass.MaxDamage;
|
|
int entityIdThatDamaged = ((ownedEntityId_ != -1 && ownedEntityId_ != -2) ? ownedEntityId_ : attackerEntityId_);
|
|
|
|
int blockDmgAmt = (attackMode_ != ItemActionAttack.EnumAttackMode.Simulate) ? blockClass.DamageBlock(world, chunkCluster.ClusterIdx, vecHitBlockPos, blockValue, (int)attackDetails_.damage, entityIdThatDamaged, attackDetails_, attackDetails_.bHarvestTool) : 0;
|
|
//Log.Out($"blockVal curBlockDmg: {curBlockDmg}, blockDmgAmt: {blockDmgAmt}");
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit blockDmgAmt: " + blockDmgAmt);
|
|
|
|
if (blockDmgAmt == 0)
|
|
{
|
|
attackDetails_.damage = 0f;
|
|
}
|
|
else
|
|
{
|
|
attackDetails_.damage -= blockDmgAmt - curBlockDmg;
|
|
}
|
|
|
|
//Log.Out("ItemActionAttackPatches-Hit curBlockDmg: " + curBlockDmg);
|
|
//Log.Out("ItemActionAttackPatches-Hit attackDetails_.damage: " + attackDetails_.damage);
|
|
|
|
if (attackMode_ != ItemActionAttack.EnumAttackMode.Simulate && isNot_RNHOE && attackingEntity is EntityPlayerLocal && blockFaceTexture > 0 && blockClass.MeshIndex == 0 && (float)blockDmgAmt >= (float)blockClass.MaxDamage * 1f)
|
|
{
|
|
try
|
|
{
|
|
ParticleEffect particleEffect = new ParticleEffect("paint_block", hitInfo_.fmcHit.pos - Origin.position, Utils.BlockFaceToRotation(hitInfo_.fmcHit.blockFace), lightValue, particleColor, null, null);
|
|
particleEffect.opqueTextureId = BlockTextureData.list[blockFaceTexture].TextureID;
|
|
GameManager.Instance.SpawnParticleEffectClient(particleEffect, attackerEntityId_);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
attackDetails_.damageGiven = (!isOverkill) ? (blockDmgAmt - curBlockDmg) : 0;
|
|
|
|
// NEW CODE - START
|
|
RebirthVariables.damageGiven = attackDetails_.damageGiven;
|
|
|
|
// NEW CODE - END
|
|
|
|
attackDetails_.damageMax = blockClass.MaxDamage;
|
|
attackDetails_.bKilled = !isOverkill && blockDmgAmt >= blockClass.MaxDamage;
|
|
attackDetails_.itemsToDrop = blockClass.itemsToDrop;
|
|
attackDetails_.bBlockHit = true;
|
|
attackDetails_.materialCategory = blockClass.blockMaterial.SurfaceCategory;
|
|
|
|
if (attackingEntity != null && attackMode_ != ItemActionAttack.EnumAttackMode.Simulate)
|
|
{
|
|
attackingEntity.MinEventContext.ItemValue = damagingItemValue_;
|
|
attackingEntity.MinEventContext.BlockValue = blockValue;
|
|
attackingEntity.MinEventContext.Tags = blockClass.Tags;
|
|
if (attackDetails_.bKilled)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfDestroyedBlock, isInventoryItem);
|
|
attackingEntity.NotifyDestroyedBlock(attackDetails_);
|
|
}
|
|
else
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfDamagedBlock, isInventoryItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Hit -> Entity
|
|
else if (hitInfo_.tag.StartsWith("E_"))
|
|
{
|
|
string bodyPartName;
|
|
Entity hitEntity = ItemActionAttack.FindHitEntityNoTagCheck(hitInfo_, out bodyPartName);
|
|
|
|
// need to check CanDamageEntity to see if it's related to no hit bug
|
|
if (hitEntity == null || hitEntity.entityId == attackerEntityId_ || !hitEntity.CanDamageEntity(attackerEntityId_)) return;
|
|
|
|
EntityAlive hitEntityAlive = hitEntity as EntityAlive;
|
|
|
|
if (attackingEntity is EntityNPCRebirth && attackingEntity.HasAnyTags(FastTags<TagGroup.Global>.Parse("ranged")))
|
|
{
|
|
int npcLevel = (int)attackingEntity.Buffs.GetCustomVar("$FR_NPC_Level");
|
|
|
|
int headshotChance = npcLevel - 1;
|
|
|
|
int random = GameManager.Instance.World.GetGameRandom().RandomRange(1, 11);
|
|
|
|
string tagName = "E_BP_Head";
|
|
|
|
if (headshotChance < random)
|
|
{
|
|
tagName = RebirthVariables.bodyTags[random];
|
|
}
|
|
|
|
float numAccuracyModifier = float.Parse(RebirthVariables.customRangedNPCAccuracyModifier) / 100;
|
|
|
|
float baseValue = 100 * numAccuracyModifier;
|
|
|
|
int numMagazineSize = 0;
|
|
float roundsPerMinute = 60;
|
|
|
|
if (numMagazineSize == 0)
|
|
{
|
|
ItemActionRanged myAction = null;
|
|
|
|
myAction = (ItemActionRanged)attackingEntity.inventory.holdingItem.Actions[1];
|
|
ItemActionData _actionData = attackingEntity.inventory.holdingItemData.actionData[1];
|
|
ItemActionRanged.ItemActionDataRanged itemActionDataRanged = (ItemActionRanged.ItemActionDataRanged)_actionData;
|
|
float myDelay = 60f / EffectManager.GetValue(PassiveEffects.RoundsPerMinute, itemActionDataRanged.invData.itemValue, 60f / itemActionDataRanged.OriginalDelay, attackingEntity);
|
|
roundsPerMinute = 60 / myDelay;
|
|
|
|
numMagazineSize = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, itemActionDataRanged.invData.itemValue, myAction.BulletsPerMagazine, attackingEntity);
|
|
}
|
|
|
|
if (numMagazineSize > 1)
|
|
{
|
|
baseValue = 60 * numAccuracyModifier;
|
|
int baseRoundsPerMinute = 60;
|
|
|
|
if (roundsPerMinute > baseRoundsPerMinute)
|
|
{
|
|
float multiplier = 1 - ((roundsPerMinute / baseRoundsPerMinute) / 15);
|
|
|
|
baseValue *= multiplier;
|
|
}
|
|
}
|
|
|
|
float missShotChance = baseValue + (npcLevel * 0.3f * numAccuracyModifier) * 10;
|
|
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget level: " + attackingEntity.Buffs.GetCustomVar("$FR_NPC_Level"));
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget A random: " + random);
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget missShotChance: " + missShotChance);
|
|
|
|
random = GameManager.Instance.World.GetGameRandom().RandomRange(1, 101);
|
|
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget B random: " + random);
|
|
|
|
if (missShotChance < random)
|
|
{
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget MISS");
|
|
return;
|
|
}
|
|
|
|
if (hitEntityAlive is EntityPlayer)
|
|
{
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget EntityName: " + hitEntityAlive.EntityName);
|
|
|
|
ProgressionValue progressionValue = hitEntityAlive.Progression.GetProgressionValue("perkDodge");
|
|
|
|
bool hitTarget = true;
|
|
|
|
if (progressionValue != null)
|
|
{
|
|
float chance = progressionValue.level * 5f;
|
|
random = GameManager.Instance.World.GetGameRandom().RandomRange(0, 101);
|
|
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget progressionValue.level: " + progressionValue.level);
|
|
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget chance: " + chance);
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget random: " + random);
|
|
|
|
if (random < chance)
|
|
{
|
|
//Log.Out("ItemActionMeleePatches-hitTheTarget EXIT");
|
|
hitTarget = false;
|
|
}
|
|
}
|
|
|
|
if (!hitTarget)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector2 uvHit = Vector2.zero;
|
|
MeshCollider meshCollider = Voxel.phyxRaycastHit.collider as MeshCollider;
|
|
|
|
if (meshCollider != null && meshCollider.sharedMesh != null && meshCollider.sharedMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.TexCoord0))
|
|
{
|
|
uvHit = Voxel.phyxRaycastHit.textureCoord;
|
|
}
|
|
|
|
DamageSourceEntity damageSourceEntity = new DamageSourceEntity(EnumDamageSource.External, damageType_, attackerEntityId_, hitInfo_.ray.direction, hitInfo_.transform.name, hitInfo_.hit.pos, uvHit);
|
|
damageSourceEntity.AttackingItem = damagingItemValue_;
|
|
damageSourceEntity.DismemberChance = dismemberChance_;
|
|
damageSourceEntity.CreatorEntityId = ownedEntityId_;
|
|
bool isCriticalHit = attackDetails_.isCriticalHit;
|
|
int entityDamage = (int)entityDamage_;
|
|
//Log.Out($"Entity Damage: {entityDamage}, attack mode: {attackMode_}");
|
|
|
|
if (attackingEntity != null && hitEntityAlive != null)
|
|
{
|
|
FastTags<TagGroup.Global> fastTags = FastTags<TagGroup.Global>.none;
|
|
if (hitEntityAlive.Health > 0)
|
|
{
|
|
fastTags = FastTags<TagGroup.Global>.Parse(damageSourceEntity.GetEntityDamageEquipmentSlotGroup(hitEntityAlive).ToStringCached());
|
|
}
|
|
entityDamage = (int)EffectManager.GetValue(PassiveEffects.DamageModifier, damagingItemValue_, entityDamage, attackingEntity, null, fastTags | attackDetails_.WeaponTypeTag | hitEntityAlive.EntityClass.Tags);
|
|
entityDamage = (int)EffectManager.GetValue(PassiveEffects.InternalDamageModifier, damagingItemValue_, entityDamage, hitEntityAlive, null, fastTags | damagingItemValue_.ItemClass.ItemTags);
|
|
}
|
|
|
|
if (!hitEntityAlive || hitEntityAlive.Health > 0)
|
|
{
|
|
entityDamage = Utils.FastMax(1, DifficultyModifier(entityDamage, world.GetEntity(attackerEntityId_), hitEntity));
|
|
}
|
|
else if (toolBonuses_ != null)
|
|
{
|
|
entityDamage = (int)(entityDamage * CalculateHarvestToolDamageBonus(toolBonuses_, EntityClass.list[hitEntity.entityClass].itemsToDrop));
|
|
}
|
|
|
|
// rebirth genetic level strengh mod
|
|
if (hitEntityAlive is EntityPlayer)
|
|
{
|
|
bool bMelee = hitEntityAlive.inventory.holdingItem.ItemTags.ToString().ToLower().Contains("melee");
|
|
if (bMelee)
|
|
{
|
|
//bool bSalvage = hitEntityAlive.inventory.holdingItem.ItemTags.ToString().ToLower().Contains("perkSalvageOperations"); // Unused at the moment?
|
|
entityDamage += entityDamage * RebirthUtilities.GetGeneticLevel("Strength") * 5 / 100;
|
|
}
|
|
}
|
|
|
|
bool hitEntityIsDead = hitEntity.IsDead();
|
|
int corpseHP = (hitEntityAlive != null) ? hitEntityAlive.DeathHealth : 0;
|
|
|
|
if (attackMode_ != ItemActionAttack.EnumAttackMode.Simulate)
|
|
{
|
|
if (attackingEntity != null)
|
|
{
|
|
MinEventParams minEventContext = attackingEntity.MinEventContext;
|
|
minEventContext.Other = hitEntityAlive;
|
|
minEventContext.ItemValue = damagingItemValue_;
|
|
minEventContext.StartPosition = hitInfo_.ray.origin;
|
|
}
|
|
|
|
if (SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer &&
|
|
(attackingEntity as EntityPlayer == null || !attackingEntity.isEntityRemote) &&
|
|
hitEntity.isEntityRemote && rangeCheckedAction_ != null)
|
|
{
|
|
EntityPlayer hitPlayer = hitEntity as EntityPlayer;
|
|
|
|
if (hitPlayer != null) // if the target is a player
|
|
{
|
|
isNotPlayerHit = false;
|
|
|
|
// to do: check entity height and get a different ray origin. look ray might be too high for certain taller entitites that would cause them to consecutively miss shorter entities
|
|
// nevermind, wrong place...
|
|
Ray lookRay = attackingEntity.GetLookRay();
|
|
lookRay.origin -= lookRay.direction * 0.15f;
|
|
float maxRange = Utils.FastMax(rangeCheckedAction_.Range, rangeCheckedAction_.BlockRange) * ItemActionAttack.attackRangeMultiplier; // Why are we multiplying by 1f?
|
|
string buffActionsContext = null;
|
|
List<string> buffActions = buffActions_;
|
|
|
|
if (buffActions != null)
|
|
{
|
|
if (hitEntityAlive != null)
|
|
{
|
|
buffActionsContext = ((bodyPartName != null) ? GameUtils.GetChildTransformPath(hitEntity.transform, hitInfo_.transform) : null);
|
|
}
|
|
else
|
|
{
|
|
buffActions = null;
|
|
}
|
|
}
|
|
|
|
if (attackingEntity != null)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfAttackedOther, isInventoryItem);
|
|
if (hitEntityAlive != null && hitEntityAlive.RecordedDamage.Strength > 0)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfDamagedOther, isInventoryItem);
|
|
}
|
|
}
|
|
|
|
if (!hitEntityIsDead && hitEntity.IsDead() && attackingEntity != null)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfKilledOther, isInventoryItem);
|
|
AddKillExpNPC(attackingNPC, hitEntityAlive);
|
|
}
|
|
|
|
surfaceCategory = ((!hitEntityAlive || hitEntityAlive.RecordedDamage.ArmorDamage <= hitEntityAlive.RecordedDamage.Strength) ? EntityClass.list[hitEntity.entityClass].Properties.Values["SurfaceCategory"] : "metal");
|
|
particleCategory = surfaceCategory;
|
|
lightValue = hitEntity.GetLightBrightness();
|
|
string particleEffectName = $"impact_{attackingDeviceMadeOf_}_on_{particleCategory}";
|
|
string soundName = ((surfaceCategory != null) ? $"{attackingDeviceMadeOf_}hit{surfaceCategory}" : null);
|
|
|
|
if (hitSoundOverrides_ != null && hitSoundOverrides_.ContainsKey(surfaceCategory))
|
|
{
|
|
soundName = hitSoundOverrides_[surfaceCategory];
|
|
}
|
|
|
|
ParticleEffect particleEffect2 = new ParticleEffect(particleEffectName, hitInfo_.fmcHit.pos, Utils.BlockFaceToRotation(hitInfo_.fmcHit.blockFace), lightValue, particleColor, soundName, null);
|
|
hitPlayer.ServerNetSendRangeCheckedDamage(lookRay.origin, maxRange, damageSourceEntity, entityDamage, isCriticalHit, buffActions, buffActionsContext, particleEffect2);
|
|
//Log.Out($"Rebirth Hit ServerNetSend - attackingEntity: {attackingEntity}, hitEntity: {hitEntity} entityDamage: {entityDamage}, stacktrace: {System.Environment.StackTrace}");
|
|
}
|
|
}
|
|
|
|
if (isNotPlayerHit)
|
|
{
|
|
// rebirth mod to recalculate damage
|
|
if (hitInfo_.tag.Equals("E_BP_Head"))
|
|
{
|
|
EntityPlayer sourcePlayer = world.GetEntity(damageSourceEntity.getEntityId()) as EntityPlayer;
|
|
|
|
if (sourcePlayer != null)
|
|
{
|
|
bool isLongRangeWeapon = sourcePlayer.inventory.holdingItem.HasAnyTags(FastTags<TagGroup.Global>.Parse("WeaponTier3LongRangeRifles"));
|
|
|
|
if (isLongRangeWeapon)
|
|
{
|
|
int activeClassID = (int)sourcePlayer.Buffs.GetCustomVar("$ActiveClass_FR");
|
|
|
|
if (RebirthUtilities.IsClassActive(activeClassID))
|
|
{
|
|
ProgressionValue progressionValue = sourcePlayer.Progression.GetProgressionValue("FuriousRamsayPerkLongRangeRifles");
|
|
if (progressionValue != null)
|
|
{
|
|
int progressionLevel = progressionValue.Level;
|
|
float damageMultiplier = progressionLevel * 0.025f;
|
|
bool isSingShotWeapon = sourcePlayer.inventory.holdingItem.HasAnyTags(FastTags<TagGroup.Global>.Parse("SingleShot"));
|
|
|
|
if (isSingShotWeapon) damageMultiplier *= 2f;
|
|
entityDamage *= (int)(1f + damageMultiplier);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int dmgResult = hitEntity.DamageEntity(damageSourceEntity, entityDamage, isCriticalHit);
|
|
//Log.Out($"Rebirth Hit - attackingEntity: {attackingEntity}, hitEntity: {hitEntity} dmg entity result: {dmgResult}, stacktrace: {System.Environment.StackTrace}");
|
|
|
|
if (dmgResult != -1 && attackingEntity != null)
|
|
{
|
|
MinEventParams minEventContext2 = attackingEntity.MinEventContext;
|
|
minEventContext2.Other = hitEntityAlive;
|
|
minEventContext2.ItemValue = damagingItemValue_;
|
|
minEventContext2.StartPosition = hitInfo_.ray.origin;
|
|
|
|
if (ownedEntityId_ != -1)
|
|
{
|
|
damagingItemValue_.FireEvent(MinEventTypes.onSelfAttackedOther, attackingEntity.MinEventContext);
|
|
}
|
|
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfAttackedOther, isInventoryItem);
|
|
|
|
if (hitEntityAlive != null && hitEntityAlive.RecordedDamage.Strength > 0)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfDamagedOther, isInventoryItem);
|
|
}
|
|
}
|
|
|
|
if (!hitEntityIsDead && hitEntity.IsDead() && attackingEntity != null)
|
|
{
|
|
attackingEntity.FireEvent(MinEventTypes.onSelfKilledOther, isInventoryItem);
|
|
AddKillExpNPC(attackingNPC, hitEntityAlive);
|
|
}
|
|
|
|
if (dmgResult != -1 && hitEntityAlive != null && buffActions_ != null && buffActions_.Count > 0)
|
|
{
|
|
for (int i = 0; i < buffActions_.Count; i++)
|
|
{
|
|
BuffClass buff = BuffManager.GetBuff(buffActions_[i]);
|
|
if (buff != null)
|
|
{
|
|
float originalValue = 1f;
|
|
originalValue = EffectManager.GetValue(PassiveEffects.BuffProcChance, null, originalValue, attackingEntity, null, FastTags<TagGroup.Global>.Parse(buff.Name));
|
|
if (hitEntityAlive.rand.RandomFloat <= originalValue)
|
|
{
|
|
hitEntityAlive.Buffs.AddBuff(buffActions_[i], attackingEntity.entityId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
surfaceCategory = (!hitEntityAlive || hitEntityAlive.RecordedDamage.ArmorDamage <= hitEntityAlive.RecordedDamage.Strength) ? EntityClass.list[hitEntity.entityClass].Properties.Values["SurfaceCategory"] : "metal";
|
|
particleCategory = surfaceCategory;
|
|
lightValue = hitEntity.GetLightBrightness();
|
|
EntityPlayer attackingPlayer = attackingEntity as EntityPlayer;
|
|
|
|
if (attackingPlayer != null) // The attacker is a Player
|
|
{
|
|
if (hitEntityIsDead && hitEntity.IsDead() && (bool)hitEntityAlive && hitEntityAlive.DeathHealth + entityDamage > -1 * EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints)
|
|
{
|
|
attackDetails_.damageTotalOfTarget = -1 * hitEntityAlive.DeathHealth;
|
|
attackDetails_.damageGiven = corpseHP + Mathf.Min(EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints, Mathf.Abs(hitEntityAlive.DeathHealth));
|
|
attackDetails_.damageMax = EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints;
|
|
attackDetails_.bKilled = -1 * hitEntityAlive.DeathHealth >= EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints;
|
|
attackDetails_.itemsToDrop = EntityClass.list[hitEntity.entityClass].itemsToDrop;
|
|
attackDetails_.entityHit = hitEntity;
|
|
attackDetails_.materialCategory = surfaceCategory;
|
|
}
|
|
|
|
if (!hitEntityIsDead && (hitEntityAlive.IsDead() || hitEntityAlive.Health <= 0) && EntityClass.list.ContainsKey(hitEntity.entityClass))
|
|
{
|
|
if ((flags_ & 2) > 0)
|
|
{
|
|
float value = EffectManager.GetValue(PassiveEffects.ElectricalTrapXP, attackingPlayer.inventory.holdingItemItemValue, 0f, attackingPlayer);
|
|
if (value > 0f)
|
|
{
|
|
if (!bypassXP)
|
|
{
|
|
attackingPlayer.AddKillXP(hitEntityAlive, value);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!bypassXP)
|
|
{
|
|
attackingPlayer.AddKillXP(hitEntityAlive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hitEntity is EntityDrone)
|
|
{
|
|
attackDetails_.entityHit = hitEntity;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
if ((flags_ & 8) > 0)
|
|
{
|
|
isNot_RNHOE = false;
|
|
}
|
|
|
|
// Spawn Particle Effect
|
|
if (isNotPlayerHit && attackMode_ != ItemActionAttack.EnumAttackMode.Simulate && isNot_RNHOE && particleCategory != null && ((attackDetails_.bBlockHit && !attackDetails_.bKilled) || !attackDetails_.bBlockHit))
|
|
{
|
|
string particleName = $"impact_{attackingDeviceMadeOf_}_on_{particleCategory}";
|
|
|
|
if (attackMode_ == ItemActionAttack.EnumAttackMode.RealAndHarvesting && (flags_ & 4) > 0 && ParticleEffect.IsAvailable(particleName + "_harvest"))
|
|
{
|
|
particleName += "_harvest";
|
|
}
|
|
|
|
string soundName2 = ((surfaceCategory != null) ? $"{attackingDeviceMadeOf_}hit{surfaceCategory}" : null);
|
|
if (hitSoundOverrides_ != null && hitSoundOverrides_.ContainsKey(surfaceCategory))
|
|
{
|
|
soundName2 = hitSoundOverrides_[surfaceCategory];
|
|
}
|
|
|
|
world.GetGameManager().SpawnParticleEffectServer(new ParticleEffect(particleName, hitInfo_.fmcHit.pos, Utils.BlockFaceToRotation(hitInfo_.fmcHit.blockFace), lightValue, particleColor, soundName2, null), attackerEntityId_, _forceCreation: false, _worldSpawn: true);
|
|
}
|
|
|
|
// Update the attacking entity's toolbelt
|
|
if ((flags_ & 1) > 0 && attackingEntity != null && attackingEntity.inventory != null)
|
|
{
|
|
attackingEntity.inventory.CallOnToolbeltChangedInternal();
|
|
}
|
|
|
|
}
|
|
|
|
static int DifficultyModifier(int _strength, Entity _attacker, Entity _target)
|
|
{
|
|
if (_attacker == null || _target == null
|
|
|| (_attacker.IsClientControlled() && _target.IsClientControlled())
|
|
|| (!_attacker.IsClientControlled() && !_target.IsClientControlled())) return _strength;
|
|
|
|
int difficultyLevel = GameStats.GetInt(EnumGameStats.GameDifficulty);
|
|
if (_attacker.IsClientControlled())
|
|
{
|
|
switch (difficultyLevel)
|
|
{
|
|
case 0:
|
|
_strength = Mathf.RoundToInt((float)_strength * 2f);
|
|
break;
|
|
case 1:
|
|
_strength = Mathf.RoundToInt((float)_strength * 1.5f);
|
|
break;
|
|
case 3:
|
|
_strength = Mathf.RoundToInt((float)_strength * 0.83f);
|
|
break;
|
|
case 4:
|
|
_strength = Mathf.RoundToInt((float)_strength * 0.66f);
|
|
break;
|
|
case 5:
|
|
_strength = Mathf.RoundToInt((float)_strength * 0.5f);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (difficultyLevel)
|
|
{
|
|
case 0:
|
|
_strength = Mathf.RoundToInt((float)_strength * 0.5f);
|
|
break;
|
|
case 1:
|
|
_strength = Mathf.RoundToInt((float)_strength * 0.75f);
|
|
break;
|
|
case 3:
|
|
_strength = Mathf.RoundToInt((float)_strength * 1.5f);
|
|
break;
|
|
case 4:
|
|
_strength = Mathf.RoundToInt((float)_strength * 2f);
|
|
break;
|
|
case 5:
|
|
_strength = Mathf.RoundToInt((float)_strength * 2.5f);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return _strength;
|
|
}
|
|
|
|
static float CalculateHarvestToolDamageBonus(Dictionary<string, ItemActionAttack.Bonuses> _toolBonuses, Dictionary<EnumDropEvent, List<Block.SItemDropProb>> _harvestItems)
|
|
{
|
|
if (!_harvestItems.ContainsKey(EnumDropEvent.Harvest)) return 1f;
|
|
|
|
List<Block.SItemDropProb> list = _harvestItems[EnumDropEvent.Harvest];
|
|
for (int i = 0; i < list.Count; i++)
|
|
{
|
|
if (list[i].toolCategory != null && _toolBonuses.ContainsKey(list[i].toolCategory))
|
|
{
|
|
return _toolBonuses[list[i].toolCategory].Damage;
|
|
}
|
|
}
|
|
|
|
return 1f;
|
|
}
|
|
|
|
static void AddKillExpNPC(EntityNPCRebirth attackingNPC, EntityAlive entityTarget)
|
|
{
|
|
if (attackingNPC == null || entityTarget == null) return;
|
|
|
|
int leaderID = RebirthUtilities.GetLeader(attackingNPC);
|
|
|
|
if (leaderID <= 0) return;
|
|
|
|
var leaderPlayer = attackingNPC.world.GetEntity(leaderID) as EntityPlayer;
|
|
|
|
if (leaderPlayer == null)
|
|
{
|
|
Log.Warning($"NPC has leader, unable to locate the player. Leader id: {leaderID}");
|
|
return;
|
|
}
|
|
|
|
float distanceEntity = leaderPlayer.GetDistance(attackingNPC);
|
|
|
|
if (distanceEntity > _KillExpMaxDist) return; // too far away
|
|
|
|
bool isNaturalSelectionCountingOn = RebirthUtilities.IsNaturalSelectionCountingOn();
|
|
|
|
/*if (isNaturalSelectionCountingOn)
|
|
{
|
|
Log.Out($"ItemActionAttackRebirth-AddKillExpNPC $NaturalSelection_FR: {leaderPlayer.Buffs.GetCustomVar("$NaturalSelection_FR")}");
|
|
|
|
int numNS = (int)leaderPlayer.Buffs.GetCustomVar("$NaturalSelection_FR") + 1;
|
|
leaderPlayer.Buffs.SetCustomVar("$NaturalSelection_FR", numNS);
|
|
RebirthVariables.localConstants["$varFuriousRamsayTheyGrowStrongerKills_Cst"] = numNS;
|
|
}*/
|
|
|
|
float expMod = _NPCKillExpMod;
|
|
|
|
if (RebirthUtilities.IsHordeNight()) expMod *= RebirthVariables.hordeNightXPMultiplier;
|
|
|
|
float partyMultiplierOption = 1; // float.Parse(RebirthVariables.customPartyXPMultiplier) / 100;
|
|
expMod = expMod * partyMultiplierOption;
|
|
|
|
float experienceGained = entityTarget.ExperienceValue * expMod;
|
|
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC entity xp: {entityTarget.ExperienceValue}");
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC partyMultiplierOption: {partyMultiplierOption}");
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC _NPCKillExpMod: {_NPCKillExpMod}");
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC _HordeNightExpMod: {RebirthVariables.hordeNightXPMultiplier}");
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC expMod: {expMod}");
|
|
//Log.Out($"ItemActionAttackRebirth-AddKillExpNPC experienceGained: {experienceGained}");
|
|
|
|
leaderPlayer.AddKillXP(entityTarget, expMod);
|
|
leaderPlayer.Progression.bProgressionStatsChanged = true;
|
|
leaderPlayer.bPlayerStatsChanged = true;
|
|
|
|
if (entityTarget is EntityPlayer)
|
|
leaderPlayer.KilledPlayers++;
|
|
else
|
|
leaderPlayer.KilledZombies++;
|
|
}
|
|
}
|
|
|