Upload from upload_mods.ps1
This commit is contained in:
42
Score/NPCv2/Scripts/Dialog/DialogActionAddItemRebirth.cs
Normal file
42
Score/NPCv2/Scripts/Dialog/DialogActionAddItemRebirth.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
public class DialogActionAddItemRebirth : DialogActionAddBuff
|
||||
{
|
||||
public override void PerformAction(EntityPlayer player)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Value))
|
||||
Value = "1";
|
||||
|
||||
int.TryParse(Value, out var flValue);
|
||||
|
||||
var uiforPlayer = LocalPlayerUI.GetUIForPlayer(player as EntityPlayerLocal);
|
||||
var playerInventory = uiforPlayer.xui.PlayerInventory;
|
||||
if (playerInventory == null) return;
|
||||
|
||||
if (ID == "FuriousRamsaySpawnCube")
|
||||
{
|
||||
int entityId = (int)player.Buffs.GetCustomVar("CurrentNPC");
|
||||
|
||||
if (entityId > 0)
|
||||
{
|
||||
var myEntity = GameManager.Instance.World.GetEntity(entityId) as EntityAliveV2;
|
||||
|
||||
if (myEntity != null)
|
||||
{
|
||||
if (myEntity.EntityClass.Properties.Values.ContainsKey("SpawnBlock"))
|
||||
{
|
||||
ID = "FuriousRamsaySpawnCube" + myEntity.EntityClass.Properties.Values["SpawnBlock"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var item = ItemClass.GetItem(ID);
|
||||
if (item == null)
|
||||
{
|
||||
Log.Out("Item Not Found: " + ID);
|
||||
return;
|
||||
}
|
||||
var itemStack = new ItemStack(item, flValue);
|
||||
if (!playerInventory.AddItem(itemStack, true))
|
||||
player.world.gameManager.ItemDropServer(itemStack, player.GetPosition(), Vector3.zero);
|
||||
}
|
||||
}
|
||||
1355
Score/NPCv2/Scripts/Entity/EntityAliveV2.cs
Normal file
1355
Score/NPCv2/Scripts/Entity/EntityAliveV2.cs
Normal file
@@ -0,0 +1,1355 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class EntityAliveV2 : EntityNPC
|
||||
{
|
||||
private PushOutOfBlocksUtils _pushOutOfBlocksUtils;
|
||||
private LeaderUtils _leaderUtils;
|
||||
private MissionUtils _missionUtils;
|
||||
private NPCUtils _npcUtils;
|
||||
|
||||
public string NewName = "";
|
||||
public string _strMyName = "Bob";
|
||||
private string _strTitle;
|
||||
public Vector3 guardPosition = Vector3.zero;
|
||||
public Vector3 guardLookPosition = Vector3.zero;
|
||||
public List<Vector3> patrolCoordinates = new List<Vector3>();
|
||||
//private bool bLastAttackReleased;
|
||||
public bool isHirable = true;
|
||||
public float flEyeHeight = -1f;
|
||||
|
||||
private string _currentWeapon = "";
|
||||
private string _defaultWeapon = "";
|
||||
//private string rightHandTransformName;
|
||||
|
||||
public QuestJournal questJournal = new QuestJournal();
|
||||
|
||||
//private string particleOnDestroy;
|
||||
//private BlockValue corpseBlockValue;
|
||||
//private float corpseBlockChance;
|
||||
|
||||
public bool isAlwaysAwake;
|
||||
|
||||
public Vector3 scale = new Vector3(1, 1, 1);
|
||||
// Toggle gravity on and off depending on if the chunk is visible.
|
||||
private ChunkCluster.OnChunkVisibleDelegate chunkClusterVisibleDelegate;
|
||||
|
||||
private TileEntity _tileEntity;
|
||||
|
||||
public override void Init(int _entityClass)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-Init START");
|
||||
base.Init(_entityClass);
|
||||
_pushOutOfBlocksUtils = new PushOutOfBlocksUtils(this);
|
||||
_npcUtils = new NPCUtils(this);
|
||||
}
|
||||
|
||||
public LeaderUtils LeaderUtils
|
||||
{
|
||||
get
|
||||
{
|
||||
return _leaderUtils;
|
||||
}
|
||||
set
|
||||
{
|
||||
_leaderUtils = value;
|
||||
}
|
||||
}
|
||||
|
||||
public MissionUtils MissionUtils
|
||||
{
|
||||
get
|
||||
{
|
||||
return _missionUtils;
|
||||
}
|
||||
set
|
||||
{
|
||||
_missionUtils = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void ConfigureBoundaryBox(Vector3 newSize, Vector3 center)
|
||||
{
|
||||
var component = gameObject.GetComponent<BoxCollider>();
|
||||
if (!component) return;
|
||||
|
||||
//Log.Out(" Box Collider: " + component.size.ToCultureInvariantString());
|
||||
//Log.Out(" Current Boundary Box: " + boundingBox.ToCultureInvariantString());
|
||||
// Re-adjusting the box collider
|
||||
component.size = newSize;
|
||||
|
||||
scaledExtent = new Vector3(component.size.x / 2f * transform.localScale.x,
|
||||
component.size.y / 2f * transform.localScale.y, component.size.z / 2f * transform.localScale.z);
|
||||
var vector = new Vector3(component.center.x * transform.localScale.x,
|
||||
component.center.y * transform.localScale.y, component.center.z * transform.localScale.z);
|
||||
boundingBox = BoundsUtils.BoundsForMinMax(-scaledExtent.x, -scaledExtent.y, -scaledExtent.z, scaledExtent.x,
|
||||
scaledExtent.y, scaledExtent.z);
|
||||
|
||||
boundingBox.center = boundingBox.center + vector;
|
||||
|
||||
if (center != Vector3.zero)
|
||||
boundingBox.center = center;
|
||||
|
||||
//Log.Out(" After BoundaryBox: " + boundingBox.ToCultureInvariantString());
|
||||
}
|
||||
|
||||
public override Ray GetLookRay()
|
||||
{
|
||||
Vector3 myHeadPos = (transform.position + new Vector3(0f, GetEyeHeight(), 0f));
|
||||
return new Ray(myHeadPos + Origin.position, GetLookVector());
|
||||
}
|
||||
|
||||
public override float GetEyeHeight()
|
||||
{
|
||||
if (!IsCrouching) return height * 0.8f;
|
||||
|
||||
return height * 0.5f;
|
||||
}
|
||||
|
||||
public override Vector3 GetLookVector()
|
||||
{
|
||||
if (attackTarget != null)
|
||||
{
|
||||
var col = attackTarget.GetComponentsInChildren<Collider>().Where(x => x.CompareTag(RebirthUtilities.GetRandomBodyTag())).FirstOrDefault();
|
||||
if (col != null)
|
||||
{
|
||||
return (col.transform.position - (transform.position + new Vector3(0f, GetEyeHeight(), 0f)));
|
||||
}
|
||||
}
|
||||
|
||||
return base.GetLookVector();
|
||||
}
|
||||
|
||||
|
||||
public virtual bool IsFriendlyPlayer(EntityPlayer player)
|
||||
{
|
||||
FactionManager.Relationship myRelationship =
|
||||
FactionManager.Instance.GetRelationshipTier(this, player);
|
||||
|
||||
if (myRelationship == FactionManager.Relationship.Love) return true; // <3
|
||||
|
||||
return false; // </3
|
||||
}
|
||||
|
||||
public override void PostInit()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-PostInit START");
|
||||
base.PostInit();
|
||||
PhysicsTransform.gameObject.SetActive(false);
|
||||
|
||||
Buffs.SetCustomVar("$waterStaminaRegenAmount", 0, false);
|
||||
SetupStartingItems();
|
||||
if (!string.IsNullOrEmpty(_currentWeapon))
|
||||
UpdateWeapon(_currentWeapon);
|
||||
inventory.SetHoldingItemIdx(0);
|
||||
|
||||
scale = transform.localScale;
|
||||
|
||||
this.PhysicsTransform.gameObject.SetActive(true);
|
||||
SetSpawnerSource(EnumSpawnerSource.Biome);
|
||||
}
|
||||
|
||||
public override void CopyPropertiesFromEntityClass()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-CopyPropertiesFromEntityClass START");
|
||||
base.CopyPropertiesFromEntityClass();
|
||||
var _entityClass = EntityClass.list[entityClass];
|
||||
|
||||
// Read in a list of names then pick one at random.
|
||||
if (_entityClass.Properties.Values.ContainsKey("Names"))
|
||||
{
|
||||
var text = _entityClass.Properties.Values["Names"];
|
||||
var names = text.Split(',');
|
||||
|
||||
var index = UnityEngine.Random.Range(0, names.Length);
|
||||
_strMyName = names[index];
|
||||
}
|
||||
|
||||
if (_entityClass.Properties.Classes.ContainsKey("Boundary"))
|
||||
{
|
||||
var strBoundaryBox = "0,0,0";
|
||||
var strCenter = "0,0,0";
|
||||
var dynamicProperties3 = _entityClass.Properties.Classes["Boundary"];
|
||||
foreach (var keyValuePair in dynamicProperties3.Values.Dict)
|
||||
{
|
||||
switch (keyValuePair.Key)
|
||||
{
|
||||
case "BoundaryBox":
|
||||
strBoundaryBox = dynamicProperties3.Values[keyValuePair.Key];
|
||||
continue;
|
||||
case "Center":
|
||||
strCenter = dynamicProperties3.Values[keyValuePair.Key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var box = StringParsers.ParseVector3(strBoundaryBox);
|
||||
var center = StringParsers.ParseVector3(strCenter);
|
||||
if (_npcUtils == null)
|
||||
_npcUtils = new NPCUtils(this);
|
||||
scaledExtent = _npcUtils.ConfigureBoundaryBox(box, center);
|
||||
}
|
||||
|
||||
/*
|
||||
* <property class="NPCConfiguration" >
|
||||
* <property name="Hireable" value="true" />
|
||||
* <property name="Missions" value="true"/>
|
||||
* </property>
|
||||
*/
|
||||
if (_entityClass.Properties.Classes.ContainsKey("NPCConfiguration"))
|
||||
{
|
||||
var dynamicProperties3 = _entityClass.Properties.Classes["NPCConfiguration"];
|
||||
foreach (var keyValuePair in dynamicProperties3.Values.Dict)
|
||||
{
|
||||
switch (keyValuePair.Key)
|
||||
{
|
||||
case "Hireable":
|
||||
if (StringParsers.ParseBool(keyValuePair.Value.ToString()))
|
||||
_leaderUtils = new LeaderUtils(this);
|
||||
continue;
|
||||
case "Missions":
|
||||
if (StringParsers.ParseBool(keyValuePair.Value.ToString()))
|
||||
{
|
||||
_missionUtils = new MissionUtils(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ExecuteAction(bool _bAttackReleased, int actionIndex)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-ExecuteAction START");
|
||||
|
||||
if (actionIndex == 0)
|
||||
{
|
||||
if (!_bAttackReleased)
|
||||
{
|
||||
if (this.emodel && this.emodel.avatarController && this.emodel.avatarController.IsAnimationAttackPlaying())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!this.IsAttackValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.bLastAttackReleased && this.GetSoundAttack() != null)
|
||||
{
|
||||
this.PlayOneShot(this.GetSoundAttack(), false);
|
||||
}
|
||||
this.bLastAttackReleased = _bAttackReleased;
|
||||
this.attackingTime = 60;
|
||||
ItemAction itemAction = this.inventory.holdingItem.Actions[actionIndex];
|
||||
if (itemAction != null)
|
||||
{
|
||||
itemAction.ExecuteAction(this.inventory.holdingItemData.actionData[actionIndex], _bAttackReleased);
|
||||
}
|
||||
}
|
||||
else if (actionIndex == 1)
|
||||
{
|
||||
if (!_bAttackReleased && !this.IsAttackValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
this.attackingTime = 60;
|
||||
if (this.inventory.holdingItem.Actions[actionIndex] != null)
|
||||
{
|
||||
this.inventory.holdingItem.Actions[actionIndex].ExecuteAction(this.inventory.holdingItemData.actionData[actionIndex], _bAttackReleased);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PlayOneShot(string clipName, bool sound_in_head = false, bool serverSignalOnly = false, bool isUnique = false)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-PlayOneShot START");
|
||||
if (IsOnMission()) return;
|
||||
base.PlayOneShot(clipName, sound_in_head);
|
||||
}
|
||||
|
||||
public override void updateStepSound(float distX, float distZ)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-updateStepSound START");
|
||||
var leader = EntityUtilities.GetLeaderOrOwner(entityId) as EntityAlive;
|
||||
if (leader == null)
|
||||
{
|
||||
base.updateStepSound(distX, distZ);
|
||||
return;
|
||||
}
|
||||
|
||||
if (leader.Buffs.GetCustomVar("quietNPC") > 0) return;
|
||||
|
||||
// Mute the foot steps when crouching.
|
||||
if (IsCrouching) return;
|
||||
|
||||
base.updateStepSound(distX, distZ);
|
||||
}
|
||||
|
||||
private bool ShouldPushOutOfBlock(int _x, int _y, int _z, bool pushOutOfTerrain)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-ShouldPushOutOfBlock START");
|
||||
var shape = world.GetBlock(_x, _y, _z).Block.shape;
|
||||
if (shape.IsSolidSpace && !shape.IsTerrain())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pushOutOfTerrain || !shape.IsSolidSpace || !shape.IsTerrain()) return false;
|
||||
var shape2 = this.world.GetBlock(_x, _y + 1, _z).Block.shape;
|
||||
return shape2.IsSolidSpace && shape2.IsTerrain();
|
||||
}
|
||||
|
||||
private bool PushOutOfBlocks(float _x, float _y, float _z)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-PushOutOfBlocks START");
|
||||
var num = Utils.Fastfloor(_x);
|
||||
var num2 = Utils.Fastfloor(_y);
|
||||
var num3 = Utils.Fastfloor(_z);
|
||||
var num4 = _x - (float)num;
|
||||
var num5 = _z - (float)num3;
|
||||
var result = false;
|
||||
if (!this.ShouldPushOutOfBlock(num, num2, num3, false) &&
|
||||
(!this.ShouldPushOutOfBlock(num, num2 + 1, num3, false))) return false;
|
||||
var flag2 = !this.ShouldPushOutOfBlock(num - 1, num2, num3, true) &&
|
||||
!this.ShouldPushOutOfBlock(num - 1, num2 + 1, num3, true);
|
||||
var flag3 = !this.ShouldPushOutOfBlock(num + 1, num2, num3, true) &&
|
||||
!this.ShouldPushOutOfBlock(num + 1, num2 + 1, num3, true);
|
||||
var flag4 = !this.ShouldPushOutOfBlock(num, num2, num3 - 1, true) &&
|
||||
!this.ShouldPushOutOfBlock(num, num2 + 1, num3 - 1, true);
|
||||
var flag5 = !this.ShouldPushOutOfBlock(num, num2, num3 + 1, true) &&
|
||||
!this.ShouldPushOutOfBlock(num, num2 + 1, num3 + 1, true);
|
||||
var b = byte.MaxValue;
|
||||
var num6 = 9999f;
|
||||
if (flag2 && num4 < num6)
|
||||
{
|
||||
num6 = num4;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
if (flag3 && 1.0 - (double)num4 < (double)num6)
|
||||
{
|
||||
num6 = 1f - num4;
|
||||
b = 1;
|
||||
}
|
||||
|
||||
if (flag4 && num5 < num6)
|
||||
{
|
||||
num6 = num5;
|
||||
b = 4;
|
||||
}
|
||||
|
||||
if (flag5 && 1f - num5 < num6)
|
||||
{
|
||||
b = 5;
|
||||
}
|
||||
|
||||
var num7 = 0.1f;
|
||||
switch (b)
|
||||
{
|
||||
case 0:
|
||||
this.motion.x = -num7;
|
||||
break;
|
||||
case 1:
|
||||
this.motion.x = num7;
|
||||
break;
|
||||
case 4:
|
||||
this.motion.z = -num7;
|
||||
break;
|
||||
case 5:
|
||||
this.motion.z = num7;
|
||||
break;
|
||||
}
|
||||
|
||||
if (b != 255)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool CheckNonSolidVertical(Vector3i blockPos, int maxY, int verticalSpace)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-CheckNonSolidVertical START");
|
||||
for (int i = 0; i < maxY; i++)
|
||||
{
|
||||
if (!this.world.GetBlock(blockPos.x, blockPos.y + i + 1, blockPos.z).Block.shape.IsSolidSpace)
|
||||
{
|
||||
bool flag = true;
|
||||
for (int j = 1; j < verticalSpace; j++)
|
||||
{
|
||||
if (this.world.GetBlock(blockPos.x, blockPos.y + i + 1 + j, blockPos.z).Block.shape.IsSolidSpace)
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void playStepSound(string stepSound)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-playStepSound START");
|
||||
if (IsOnMission()) return;
|
||||
if (HasAnyTags(FastTags<TagGroup.Global>.Parse("floating"))) return;
|
||||
|
||||
base.playStepSound(stepSound);
|
||||
}
|
||||
|
||||
public override bool IsAttackValid()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-IsAttackValid START");
|
||||
if (IsOnMission()) return false;
|
||||
return base.IsAttackValid();
|
||||
}
|
||||
|
||||
// Helper Method is maintain backwards compatibility, while also pushing the code out to another class to clean it up.
|
||||
// NEW - CHANGE from Private to Public for access from LeaderUtils
|
||||
public bool IsOnMission()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-IsOnMission START");
|
||||
if (_missionUtils == null) return false;
|
||||
return _missionUtils.IsOnMission();
|
||||
}
|
||||
|
||||
// Helper Method is maintain backwards compatibility, while also pushing the code out to another class to clean it up.
|
||||
public void SendOnMission(bool send)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SendOnMission START");
|
||||
_npcUtils?.ToggleCollisions(!send);
|
||||
_missionUtils?.SendOnMission(send);
|
||||
}
|
||||
|
||||
public new void SetAttackTarget(EntityAlive _attackTarget, int _attackTargetTime)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SetAttackTarget START");
|
||||
if (_attackTarget != null && _attackTarget.IsDead()) return;
|
||||
|
||||
if (IsOnMission())
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SetAttackTarget IS ON MISSION");
|
||||
return;
|
||||
}
|
||||
|
||||
// Some of the AI tasks resets the attack target when it falls down stunned; this will prevent the NPC from ignoring its stunned opponent.
|
||||
if (_attackTarget == null)
|
||||
{
|
||||
//Log.Out($"EntityAliveV2-SetAttackTarget SPECIFIED ATTACK TARGET == null this: {this}, _attackTarget: {_attackTarget}, attackTarget: {attackTarget}");
|
||||
|
||||
if (attackTarget != null && attackTarget.IsAlive())
|
||||
{
|
||||
//Log.Out($"EntityAliveV2-SetAttackTarget KEEP CURRENT TARGET: {attackTarget}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Log.Out($"EntityAliveV2-SetAttackTarget END this: {this}, calling base.SetAttackTarget USE NEW TARGET: {_attackTarget}, _attackTargetTime: {_attackTargetTime}");
|
||||
|
||||
base.SetAttackTarget(_attackTarget, _attackTargetTime);
|
||||
}
|
||||
|
||||
public new void SetRevengeTarget(EntityAlive _other)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SetRevengeTarget START");
|
||||
if (IsOnMission()) return;
|
||||
base.SetRevengeTarget(_other);
|
||||
}
|
||||
|
||||
public override void ProcessDamageResponse(DamageResponse _dmResponse)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-ProcessDamageResponse START");
|
||||
if (IsOnMission()) return;
|
||||
base.ProcessDamageResponse(_dmResponse);
|
||||
}
|
||||
|
||||
public override bool IsImmuneToLegDamage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsOnMission()) return true;
|
||||
return base.IsImmuneToLegDamage;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ProcessDamageResponseLocal(DamageResponse _dmResponse)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-ProcessDamageResponseLocal START");
|
||||
if (EntityUtilities.GetBoolValue(entityId, "Invulnerable")) return;
|
||||
if (Buffs.HasBuff("buffInvulnerable")) return;
|
||||
|
||||
if (!isEntityRemote)
|
||||
{
|
||||
// If we are being attacked, let the state machine know it can fight back
|
||||
emodel.avatarController.UpdateBool("IsBusy", false);
|
||||
}
|
||||
|
||||
base.ProcessDamageResponseLocal(_dmResponse);
|
||||
}
|
||||
|
||||
public override void MarkToUnload()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-MarkToUnload START");
|
||||
if (!bWillRespawn)
|
||||
{
|
||||
base.MarkToUnload();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanBePushed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override float getNextStepSoundDistance()
|
||||
{
|
||||
return !IsRunning ? 0.5f : 0.25f;
|
||||
}
|
||||
|
||||
public virtual bool ShouldDamage(EntityAlive sourceEntity)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-ShouldDamage START");
|
||||
return EntityTargetingUtilities.CanTakeDamage(this, sourceEntity);
|
||||
}
|
||||
|
||||
public override int DamageEntity(DamageSource _damageSource, int _strength, bool _criticalHit, float _impulseScale)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-DamageEntity START");
|
||||
if (IsOnMission()) return 0;
|
||||
|
||||
if (EntityUtilities.GetBoolValue(entityId, "Invulnerable"))
|
||||
{
|
||||
//Log.Out("EntityAliveV2-DamageEntity 1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Buffs.HasBuff("buffInvulnerable"))
|
||||
{
|
||||
//Log.Out("EntityAliveV2-DamageEntity 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_damageSource.damageType == EnumDamageTypes.Falling &&
|
||||
this.Buffs.HasCustomVar("$Leader")
|
||||
)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-DamageEntity 3");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Faction check
|
||||
bool shouldDamage = ShouldDamage((EntityAlive)world.GetEntity(_damageSource.getEntityId()));
|
||||
|
||||
//Log.Out("EntityAliveV2-DamageEntity shouldDamage: " + shouldDamage);
|
||||
|
||||
if (!shouldDamage)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-DamageEntity 4");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var damage = base.DamageEntity(_damageSource, _strength, _criticalHit, _impulseScale);
|
||||
return damage;
|
||||
}
|
||||
|
||||
public override void SetDead()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SetDead START");
|
||||
_leaderUtils?.SetDead();
|
||||
|
||||
bWillRespawn = false;
|
||||
if (NavObject != null)
|
||||
{
|
||||
NavObjectManager.Instance.UnRegisterNavObject(NavObject);
|
||||
NavObject = null;
|
||||
}
|
||||
|
||||
SetupDebugNameHUD(false);
|
||||
|
||||
lootContainer = null;
|
||||
lootListAlive = null;
|
||||
lootListOnDeath = null;
|
||||
isCollided = false;
|
||||
nativeCollider = null;
|
||||
physicsCapsuleCollider = null;
|
||||
|
||||
var component = gameObject.GetComponentsInChildren<Collider>();
|
||||
|
||||
foreach (var t in component)
|
||||
{
|
||||
if (t.name.ToLower() == "gameobject")
|
||||
{
|
||||
t.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetDead();
|
||||
}
|
||||
|
||||
public virtual void TeleportToPlayer(EntityAlive target, bool randomPosition = false)
|
||||
{
|
||||
_leaderUtils?.TeleportToPlayer(target, randomPosition);
|
||||
}
|
||||
|
||||
|
||||
public override string EntityName
|
||||
{
|
||||
get
|
||||
{
|
||||
// No configured name? return the default.
|
||||
if (_strMyName == "Bob")
|
||||
return entityName;
|
||||
|
||||
if (string.IsNullOrEmpty(_strTitle))
|
||||
return Localization.Get(_strMyName);
|
||||
return Localization.Get(_strMyName) + " the " + Localization.Get(_strTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetEntityName(string _name)
|
||||
{
|
||||
if (_name.Equals(entityName)) return;
|
||||
|
||||
entityName = _name;
|
||||
|
||||
// Don't set the internal name if it's the name of the entity class, since the
|
||||
// EntityFactory calls the setter with the class name when it creates the entity.
|
||||
// But set the internal name otherwise, because the setter is also called when the
|
||||
// entity is re-created after being picked up and placed again.
|
||||
if (_name?.Equals(EntityClass.list[entityClass].entityClassName) != true)
|
||||
{
|
||||
_strMyName = _name;
|
||||
}
|
||||
|
||||
bPlayerStatsChanged |= !isEntityRemote;
|
||||
HandleSetNavName();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter _bw, bool bNetworkWrite)
|
||||
{
|
||||
base.Write(_bw, bNetworkWrite);
|
||||
if (NewName != "")
|
||||
{
|
||||
_bw.Write(NewName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bw.Write(_strMyName);
|
||||
}
|
||||
|
||||
_bw.Write(factionId);
|
||||
_bw.Write(scale.ToString());
|
||||
|
||||
var strPatrolCoordinates = "";
|
||||
foreach (var temp in patrolCoordinates) strPatrolCoordinates += ";" + temp;
|
||||
|
||||
_bw.Write(strPatrolCoordinates);
|
||||
_bw.Write(guardPosition.ToString());
|
||||
_bw.Write(guardLookPosition.ToString());
|
||||
Buffs.Write(_bw);
|
||||
_bw.Write(inventory.holdingItem.GetItemName());
|
||||
//WriteSyncData(_bw, 1);
|
||||
}
|
||||
|
||||
public override void Read(byte _version, BinaryReader _br)
|
||||
{
|
||||
base.Read(_version, _br);
|
||||
_strMyName = _br.ReadString();
|
||||
factionId = _br.ReadByte();
|
||||
scale = RebirthUtilities.StringToVector3(_br.ReadString());
|
||||
|
||||
patrolCoordinates.Clear();
|
||||
var strPatrol = _br.ReadString();
|
||||
foreach (var strPatrolPoint in strPatrol.Split(';'))
|
||||
{
|
||||
var temp = ModGeneralUtilities.StringToVector3(strPatrolPoint);
|
||||
if (temp != Vector3.zero)
|
||||
patrolCoordinates.Add(temp);
|
||||
}
|
||||
|
||||
var strGuardPosition = _br.ReadString();
|
||||
guardPosition = ModGeneralUtilities.StringToVector3(strGuardPosition);
|
||||
guardLookPosition = ModGeneralUtilities.StringToVector3(_br.ReadString());
|
||||
Buffs.Read(_br);
|
||||
|
||||
_currentWeapon = _br.ReadString();
|
||||
UpdateWeapon(_currentWeapon);
|
||||
//ReadSyncData(_br, 1, -1);
|
||||
}
|
||||
|
||||
public override bool CanEntityJump()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnUpdateLive()
|
||||
{
|
||||
_leaderUtils?.LeaderUpdate();
|
||||
_pushOutOfBlocksUtils.CheckStuck(position, width, depth);
|
||||
_npcUtils?.CheckCollision();
|
||||
_npcUtils?.CheckFallAndGround();
|
||||
|
||||
// Set CanFall and IsOnGround
|
||||
if (emodel != null && emodel.avatarController != null)
|
||||
{
|
||||
emodel.avatarController.UpdateBool("CanFall",
|
||||
!emodel.IsRagdollActive && bodyDamage.CurrentStun == EnumEntityStunType.None && !isSwimming);
|
||||
emodel.avatarController.UpdateBool("IsOnGround", onGround || isSwimming);
|
||||
}
|
||||
|
||||
if (IsOnMission())
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnUpdateLive ON MISSION");
|
||||
if (transform.localScale != Vector3.zero)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnUpdateLive A transform.localScale: " + transform.localScale);
|
||||
transform.localScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnUpdateLive NOT ON MISSION");
|
||||
if (transform.localScale != scale)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnUpdateLive B transform.localScale: " + transform.localScale);
|
||||
//Log.Out("EntityAliveV2-OnUpdateLive scale: " + scale);
|
||||
transform.localScale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnUpdateLive();
|
||||
}
|
||||
|
||||
public override EntityActivationCommand[] GetActivationCommands(Vector3i _tePos, EntityAlive _entityFocusing)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-GetActivationCommands START");
|
||||
if (this.IsDead() || NPCInfo == null)
|
||||
{
|
||||
//Debug.Log("NPC info == null.");
|
||||
return new EntityActivationCommand[0];
|
||||
}
|
||||
|
||||
return new EntityActivationCommand[] {
|
||||
new EntityActivationCommand("talk", "talk", true),
|
||||
new EntityActivationCommand("talk", "talk", true),
|
||||
new EntityActivationCommand("talk", "talk", true)
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public override bool OnEntityActivated(int _indexInBlockActivationCommands, Vector3i _tePos, EntityAlive _entityFocusing)
|
||||
{
|
||||
EntityPlayerLocal player = (EntityPlayerLocal)_entityFocusing;
|
||||
|
||||
if (!player)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnEntityActivated 1");
|
||||
//Log.Out($"!player");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.PlayerUI.windowManager.IsWindowOpen("dialog"))
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnEntityActivated 2");
|
||||
//Log.Out($"IsWindowOpen dialog");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EntityUtilities.VerifyFactionStanding(_entityFocusing, this))
|
||||
{
|
||||
//Log.Out($"Not VerifyFactionStanding");
|
||||
return false;
|
||||
}
|
||||
|
||||
float leader = this.Buffs.GetCustomVar("$Leader");
|
||||
|
||||
if (leader > 0 && leader != _entityFocusing.entityId)
|
||||
{
|
||||
//Log.Out($"leader: {leader}, _entityFocusing.entityId: {_entityFocusing.entityId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Buffs.AddBuff("buffTalkingTo");
|
||||
RotateTo(_entityFocusing, 360f, 360f);
|
||||
SetLookPosition(_entityFocusing.getHeadPosition());
|
||||
|
||||
//Log.Out($"{_entityFocusing} talking to {entityId}");
|
||||
|
||||
_entityFocusing.Buffs.SetCustomVar("CurrentNPC", this.entityId);
|
||||
RebirthVariables.talkingToNPC = this.entityId;
|
||||
|
||||
Buffs.SetCustomVar("CurrentPlayer", _entityFocusing.entityId);
|
||||
|
||||
var uiforPlayer = LocalPlayerUI.GetUIForPlayer(_entityFocusing as EntityPlayerLocal);
|
||||
uiforPlayer.xui.Dialog.Respondent = this;
|
||||
uiforPlayer.windowManager.CloseAllOpenWindows(null, false);
|
||||
uiforPlayer.windowManager.Open("dialog", true, false, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper Method to access the protected HandleNavObject of the base class
|
||||
public new void HandleNavObject()
|
||||
{
|
||||
base.HandleNavObject();
|
||||
}
|
||||
|
||||
// We don't have access to JumpState outside of the class, so we can make a nifty public helper to get the value.
|
||||
public JumpState GetJumpState()
|
||||
{
|
||||
return jumpState;
|
||||
}
|
||||
|
||||
public virtual TileEntity GetTileEntity()
|
||||
{
|
||||
var chunk = GameManager.Instance.World.GetChunkFromWorldPos(World.worldToBlockPos(position)) as Chunk;
|
||||
|
||||
if (_tileEntity == null)
|
||||
{
|
||||
// TileEntityAoE is a basic tile entity, so we are just re-using it.
|
||||
_tileEntity = new TileEntityAoE(chunk)
|
||||
{
|
||||
entityId = entityId
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
_tileEntity.SetChunk(chunk);
|
||||
}
|
||||
|
||||
return _tileEntity;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// This is an attempt at turning off gravity for the entity when chunks are no longer visible. The hope is that it will resolve the disappearing NPCs.
|
||||
public void OnChunkDisplayed(long _key, bool _bDisplayed)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnChunkDisplayed START");
|
||||
if (this.emodel == null) return;
|
||||
var modelTransform = this.emodel.GetModelTransform();
|
||||
if (modelTransform == null) return;
|
||||
foreach (var rigid in modelTransform.GetComponentsInChildren<Rigidbody>())
|
||||
{
|
||||
rigid.useGravity = _bDisplayed;
|
||||
}
|
||||
}
|
||||
|
||||
public override void dropItemOnDeath()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-dropItemOnDeath START");
|
||||
// Don't drop your toolbelt
|
||||
if (this.world.IsDark())
|
||||
{
|
||||
this.lootDropProb *= 1f;
|
||||
}
|
||||
|
||||
if (this.entityThatKilledMe)
|
||||
{
|
||||
this.lootDropProb = EffectManager.GetValue(PassiveEffects.LootDropProb,
|
||||
this.entityThatKilledMe.inventory.holdingItemItemValue, this.lootDropProb, this.entityThatKilledMe,
|
||||
null, new FastTags<TagGroup.Global>(), true, true, true, true, true, 1);
|
||||
}
|
||||
|
||||
if (this.lootDropProb > this.rand.RandomFloat)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-dropItemOnDeath DROP LOOT CONTAINER");
|
||||
GameManager.Instance.DropContentOfLootContainerServer(BlockValue.Air, new Vector3i(this.position),
|
||||
this.entityId);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public override void OnAddedToWorld()
|
||||
{
|
||||
if (isAlwaysAwake)
|
||||
{
|
||||
// Set the current order, defaults to "Wander"
|
||||
// EntityUtilities.SetCurrentOrder(entityId, EntityUtilities.GetCurrentOrder(entityId));
|
||||
|
||||
// Set in EntityAlive.TriggerSleeperPose() - resetting here
|
||||
IsSleeping = false;
|
||||
}
|
||||
|
||||
this.chunkClusterVisibleDelegate = new ChunkCluster.OnChunkVisibleDelegate(this.OnChunkDisplayed);
|
||||
|
||||
GameManager.Instance.World.ChunkClusters[0].OnChunkVisibleDelegates += this.chunkClusterVisibleDelegate;
|
||||
base.OnAddedToWorld();
|
||||
AddToInventory();
|
||||
|
||||
if (this.lootContainer == null)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnAddedToWorld this.lootContainer == null");
|
||||
this.lootContainer = new TileEntityLootContainer((Chunk)null);
|
||||
this.lootContainer.entityId = this.entityId;
|
||||
|
||||
string lootListName = this.GetLootList();
|
||||
|
||||
this.lootContainer.lootListName = lootListName; // lootContainer.Name;
|
||||
|
||||
LootContainer lootContainer = LootContainer.GetLootContainer(lootListName, true);
|
||||
|
||||
Vector2i size = new Vector2i(0, 0);
|
||||
|
||||
if (lootContainer == null)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnAddedToWorld entityClassName: " + this.EntityClass.entityClassName);
|
||||
//Log.Out("EntityAliveV2-OnAddedToWorld EntityName: " + this.EntityName);
|
||||
//Log.Out("EntityAliveV2-OnAddedToWorld lootListName: " + lootListName);
|
||||
size = new Vector2i(8, 6);
|
||||
//throw new Exception("NPC LOOT LIST APPEARS TO BE INVALID");
|
||||
}
|
||||
else
|
||||
{
|
||||
size = lootContainer.size;
|
||||
}
|
||||
|
||||
this.lootContainer.SetContainerSize(size, true);
|
||||
this.bag.SetupSlots(ItemStack.CreateArray(size.x * size.y));
|
||||
}
|
||||
if (lootContainer != null)
|
||||
{
|
||||
this.lootContainer.bWasTouched = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CheckStuck()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-CheckStuck START");
|
||||
IsStuck = false;
|
||||
if (IsFlyMode.Value) return;
|
||||
var num = boundingBox.min.y + 0.5f;
|
||||
IsStuck = PushOutOfBlocks(position.x - width * 0.3f, num, position.z + depth * 0.3f);
|
||||
IsStuck = (PushOutOfBlocks(position.x - width * 0.3f, num, position.z - depth * 0.3f) || IsStuck);
|
||||
IsStuck = (PushOutOfBlocks(position.x + width * 0.3f, num, position.z - depth * 0.3f) || IsStuck);
|
||||
IsStuck = (PushOutOfBlocks(position.x + width * 0.3f, num, position.z + depth * 0.3f) || IsStuck);
|
||||
if (IsStuck) return;
|
||||
|
||||
var x = Utils.Fastfloor(position.x);
|
||||
var num2 = Utils.Fastfloor(num);
|
||||
var z = Utils.Fastfloor(position.z);
|
||||
if (!ShouldPushOutOfBlock(x, num2, z, true) ||
|
||||
!CheckNonSolidVertical(new Vector3i(x, num2 + 1, z), 4, 2)) return;
|
||||
IsStuck = true;
|
||||
motion = new Vector3(0f, 1.6f, 0f);
|
||||
Log.Warning($"{EntityName} ({entityId}) is stuck. Unsticking.");
|
||||
}
|
||||
|
||||
private void AddToInventory()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-AddToInventory START");
|
||||
// We only want to fire the initial inventory once per entity creation.
|
||||
// Let's gate it using a cvar
|
||||
if (Buffs.GetCustomVar("InitialInventory") > 0) return;
|
||||
Buffs.SetCustomVar("InitialInventory", 1);
|
||||
var currentEntityClass = EntityClass.list[entityClass];
|
||||
if (currentEntityClass.Properties.Values.ContainsKey("StartingItems"))
|
||||
{
|
||||
var text = currentEntityClass.Properties.Values["StartingItems"];
|
||||
var items = text.Split(',');
|
||||
foreach (var item in items)
|
||||
{
|
||||
var itemStack = ItemStack.FromString(item.Trim());
|
||||
if (itemStack.itemValue.IsEmpty()) continue;
|
||||
var forId = ItemClass.GetForId(itemStack.itemValue.type);
|
||||
if (forId.HasQuality)
|
||||
{
|
||||
itemStack.itemValue = new ItemValue(itemStack.itemValue.type, 1, 6, false, null, 1f);
|
||||
}
|
||||
|
||||
lootContainer.AddItem(itemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SetupStartingItems()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-SetupStartingItems START");
|
||||
for (var i = 0; i < this.itemsOnEnterGame.Count; i++)
|
||||
{
|
||||
var itemStack = this.itemsOnEnterGame[i];
|
||||
var forId = ItemClass.GetForId(itemStack.itemValue.type);
|
||||
if (forId.HasQuality)
|
||||
{
|
||||
itemStack.itemValue = new ItemValue(itemStack.itemValue.type, 1, 6, false, null, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemStack.count = forId.Stacknumber.Value;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
_defaultWeapon = forId.GetItemName();
|
||||
inventory.SetItem(i, itemStack);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshWeapon()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-RefreshWeapon START");
|
||||
var item = ItemClass.GetItem(_currentWeapon);
|
||||
UpdateWeapon(item);
|
||||
}
|
||||
|
||||
public void UpdateWeapon(string itemName = "")
|
||||
{
|
||||
//Log.Out("EntityAliveV2-UpdateWeapon START");
|
||||
if (string.IsNullOrEmpty(itemName))
|
||||
itemName = _currentWeapon;
|
||||
|
||||
var item = ItemClass.GetItem(itemName);
|
||||
UpdateWeapon(item);
|
||||
EntityUtilities.UpdateHandItem(entityId, itemName);
|
||||
}
|
||||
|
||||
// Allows the NPC to change their hand items, and update their animator.
|
||||
public void UpdateWeapon(ItemValue item)
|
||||
{
|
||||
return; // todo fix?
|
||||
|
||||
if (item == null) return;
|
||||
if (item.GetItemId() < 0) return;
|
||||
_currentWeapon = item.ItemClass.GetItemName();
|
||||
|
||||
// Do we have this item?
|
||||
if (!FindWeapon(_currentWeapon))
|
||||
{
|
||||
Debug.Log($"EntityAliveV2: UpdateWeapon() Item not found: {_currentWeapon}");
|
||||
if (string.IsNullOrEmpty(_defaultWeapon))
|
||||
return;
|
||||
|
||||
// Switch to default
|
||||
item = ItemClass.GetItem(_defaultWeapon);
|
||||
}
|
||||
|
||||
if (item.GetItemId() == inventory.holdingItemItemValue.GetItemId())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentWeapon = item.ItemClass.GetItemName();
|
||||
Buffs.SetCustomVar("CurrentWeaponID", item.GetItemId());
|
||||
inventory.SetItem(0, item, 1);
|
||||
|
||||
foreach (var action in item.ItemClass.Actions)
|
||||
{
|
||||
if (action is ItemActionRanged ranged)
|
||||
{
|
||||
ranged.AutoFire = new DataItem<bool>(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Since we are potentially changing the Hand Transform, we need to set the animator it changed.
|
||||
var entityClassType = EntityClass.list[entityClass];
|
||||
emodel.avatarController.SwitchModelAndView(entityClassType.mesh.name, emodel.IsFPV, IsMale);
|
||||
|
||||
// Item update has to happen after the SwitchModelAndView, otherwise the weapon will attach to the previous hand position
|
||||
inventory.OnUpdate();
|
||||
inventory.ForceHoldingItemUpdate();
|
||||
}
|
||||
|
||||
public virtual void Collect(int _playerId)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-Collect START");
|
||||
var entityPlayerLocal = world.GetEntity(_playerId) as EntityPlayerLocal;
|
||||
if (entityPlayerLocal == null) return;
|
||||
var uiforPlayer = LocalPlayerUI.GetUIForPlayer(entityPlayerLocal);
|
||||
var itemStack = new ItemStack(GetItemValue(), 1);
|
||||
if (!uiforPlayer.xui.PlayerInventory.AddItem(itemStack))
|
||||
{
|
||||
GameManager.Instance.ItemDropServer(itemStack, entityPlayerLocal.GetPosition(), Vector3.zero, _playerId,
|
||||
60f, false);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetItemValue(ItemValue itemValue)
|
||||
{
|
||||
Log.Out("EntityAliveV2-SetItemValue START");
|
||||
SetEntityName(itemValue.GetMetadata("NPCName") as string);
|
||||
belongsPlayerId = (int)itemValue.GetMetadata("BelongsToPlayer");
|
||||
Health = (int)itemValue.GetMetadata("health");
|
||||
var leaderID = (int)itemValue.GetMetadata("Leader");
|
||||
EntityUtilities.SetLeaderAndOwner(entityId, leaderID);
|
||||
|
||||
lootContainer.entityId = entityId;
|
||||
var slots = lootContainer.items;
|
||||
for (var i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var key = $"LootContainer-{i}";
|
||||
var storage = itemValue.GetMetadata(key)?.ToString();
|
||||
if (string.IsNullOrEmpty(storage)) continue;
|
||||
|
||||
var itemId = storage.Split(',')[0];
|
||||
var quality = StringParsers.ParseSInt32(storage.Split(',')[1]);
|
||||
var itemCount = StringParsers.ParseSInt32(storage.Split(',')[2]);
|
||||
var createItem = ItemClass.GetItem(itemId);
|
||||
if (storage.Split(',').Length > 3)
|
||||
{
|
||||
var useTime = StringParsers.ParseFloat(storage.Split(',')[3]);
|
||||
createItem.UseTimes = useTime;
|
||||
}
|
||||
|
||||
createItem.Quality = (ushort)quality;
|
||||
var stack = new ItemStack(createItem, itemCount);
|
||||
lootContainer.AddItem(stack);
|
||||
}
|
||||
|
||||
// Tool belt
|
||||
slots = inventory.GetSlots();
|
||||
for (var i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var key = $"InventorySlot-{i}";
|
||||
var storage = itemValue.GetMetadata(key)?.ToString();
|
||||
if (string.IsNullOrEmpty(storage)) continue;
|
||||
|
||||
var itemId = storage.Split(',')[0];
|
||||
var quality = StringParsers.ParseSInt32(storage.Split(',')[1]);
|
||||
var itemCount = StringParsers.ParseSInt32(storage.Split(',')[2]);
|
||||
var createItem = ItemClass.GetItem(itemId);
|
||||
createItem.Quality = (ushort)quality;
|
||||
var stack = new ItemStack(createItem, itemCount);
|
||||
inventory.SetItem(i, stack);
|
||||
}
|
||||
|
||||
var x = (int)itemValue.GetMetadata("TotalBuff");
|
||||
for (var i = 0; i < x; i++)
|
||||
{
|
||||
var buffName = itemValue.GetMetadata($"Buff-{i}")?.ToString();
|
||||
Buffs.AddBuff(buffName);
|
||||
}
|
||||
|
||||
x = (int)itemValue.GetMetadata("TotalCVar");
|
||||
for (var i = 0; i < x; i++)
|
||||
{
|
||||
var cvarData = itemValue.GetMetadata($"CVar-{i}")?.ToString();
|
||||
if (cvarData == null) continue;
|
||||
|
||||
var cvarName = cvarData.Split(':')[0];
|
||||
var cvarValue = cvarData.Split(':')[1];
|
||||
Buffs.AddCustomVar(cvarName, StringParsers.ParseFloat(cvarValue));
|
||||
}
|
||||
|
||||
var weaponType = itemValue.GetMetadata("CurrentWeapon").ToString();
|
||||
_defaultWeapon = itemValue.GetMetadata("DefaultWeapon").ToString();
|
||||
var item = ItemClass.GetItem(weaponType);
|
||||
if (item != null)
|
||||
{
|
||||
UpdateWeapon(item);
|
||||
}
|
||||
|
||||
Buffs.SetCustomVar("WeaponTypeNeedsUpdate", 1);
|
||||
}
|
||||
|
||||
public virtual ItemValue GetItemValue()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-GetItemValue START");
|
||||
var type = 0;
|
||||
|
||||
var itemValue = new ItemValue(type, false);
|
||||
//itemValue.SetMetadata("NPCName", EntityName, TypedMetadataValue.TypeTag.String);
|
||||
itemValue.SetMetadata("EntityClassId", entityClass, TypedMetadataValue.TypeTag.Integer);
|
||||
itemValue.SetMetadata("BelongsToPlayer", belongsPlayerId, TypedMetadataValue.TypeTag.Integer);
|
||||
itemValue.SetMetadata("health", Health, TypedMetadataValue.TypeTag.Integer);
|
||||
itemValue.SetMetadata("Leader", EntityUtilities.GetLeaderOrOwner(entityId)?.entityId,
|
||||
TypedMetadataValue.TypeTag.Integer);
|
||||
itemValue.SetMetadata("CurrentWeapon", inventory.holdingItem.GetItemName(), TypedMetadataValue.TypeTag.String);
|
||||
itemValue.SetMetadata("DefaultWeapon", _defaultWeapon, TypedMetadataValue.TypeTag.String);
|
||||
if (lootContainer == null) return itemValue;
|
||||
|
||||
var slots = lootContainer.items;
|
||||
for (var i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (slots[i].IsEmpty()) continue;
|
||||
var itemId = slots[i].itemValue.ItemClass.GetItemName();
|
||||
var quality = slots[i].itemValue.Quality;
|
||||
var itemCount = slots[i].count;
|
||||
var itemUse = slots[i].itemValue.UseTimes;
|
||||
var storage = $"{itemId},{quality},{itemCount},{itemUse}";
|
||||
itemValue.SetMetadata($"LootContainer-{i}", storage, TypedMetadataValue.TypeTag.String);
|
||||
}
|
||||
|
||||
// Tool belt
|
||||
slots = inventory.GetSlots();
|
||||
for (var i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (slots[i].IsEmpty()) continue;
|
||||
var itemId = slots[i].itemValue.ItemClass.GetItemName();
|
||||
var quality = slots[i].itemValue.Quality;
|
||||
var itemCount = slots[i].count;
|
||||
var itemUse = slots[i].itemValue.UseTimes;
|
||||
var storage = $"{itemId},{quality},{itemCount},{itemUse}";
|
||||
itemValue.SetMetadata($"InventorySlot-{i}", storage, TypedMetadataValue.TypeTag.String);
|
||||
}
|
||||
|
||||
var x = 0;
|
||||
itemValue.SetMetadata($"TotalBuff", Buffs.ActiveBuffs.Count, TypedMetadataValue.TypeTag.Integer);
|
||||
foreach (var buff in Buffs.ActiveBuffs)
|
||||
{
|
||||
itemValue.SetMetadata($"Buff-{x}", buff.BuffName, TypedMetadataValue.TypeTag.String);
|
||||
x++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
itemValue.SetMetadata($"TotalCVar", Buffs.CVars.Count, TypedMetadataValue.TypeTag.Integer);
|
||||
foreach (var cvar in Buffs.CVars)
|
||||
{
|
||||
var value = $"{cvar.Key}:{cvar.Value}";
|
||||
itemValue.SetMetadata($"CVar-{x}", value, TypedMetadataValue.TypeTag.String);
|
||||
x++;
|
||||
}
|
||||
|
||||
return itemValue;
|
||||
}
|
||||
|
||||
public bool FindWeapon(string weapon)
|
||||
{
|
||||
//Log.Out("EntityAliveV2-FindWeapon START");
|
||||
var currentWeapon = ItemClass.GetItem(weapon);
|
||||
if (currentWeapon == null) return false;
|
||||
if (!currentWeapon.ItemClass.Properties.Contains("CompatibleWeapon")) return false;
|
||||
var playerWeapon = currentWeapon.ItemClass.Properties.GetStringValue("CompatibleWeapon");
|
||||
if (string.IsNullOrEmpty(playerWeapon)) return false;
|
||||
var playerWeaponItem = ItemClass.GetItem(playerWeapon);
|
||||
if (playerWeaponItem == null) return false;
|
||||
if (lootContainer != null)
|
||||
{
|
||||
if (lootContainer.HasItem(playerWeaponItem))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we don't have it in our loot container, check to see if we had it when we first spawned in.
|
||||
for (var i = 0; i < itemsOnEnterGame.Count; i++)
|
||||
{
|
||||
var itemStack = itemsOnEnterGame[i];
|
||||
if (itemStack.itemValue.ItemClass.GetItemName()
|
||||
.Equals(weapon, StringComparison.InvariantCultureIgnoreCase)) return true;
|
||||
}
|
||||
|
||||
if (GetHandItem().ItemClass.GetItemName().Equals(weapon, StringComparison.InvariantCultureIgnoreCase))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The GetRightHandTransformName() is not virtual in the base class. There's a Harmony patch that redirects the AvatarAnimator's call here.
|
||||
// This helps adjust the hand position for various weapons we can add to the NPC.
|
||||
public new string GetRightHandTransformName()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-GetRightHandTransformName START");
|
||||
var currentItemHand = inventory.holdingItem;
|
||||
if (currentItemHand.Properties.Contains(EntityClass.PropRightHandJointName))
|
||||
{
|
||||
currentItemHand.Properties.ParseString(EntityClass.PropRightHandJointName, ref rightHandTransformName);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightHandTransformName = "Gunjoint";
|
||||
EntityClass.list[entityClass].Properties
|
||||
.ParseString(EntityClass.PropRightHandJointName, ref rightHandTransformName);
|
||||
}
|
||||
|
||||
return rightHandTransformName;
|
||||
}
|
||||
|
||||
public override void OnDeathUpdate()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-OnDeathUpdate START");
|
||||
if (this.deathUpdateTime < this.timeStayAfterDeath)
|
||||
{
|
||||
this.deathUpdateTime++;
|
||||
}
|
||||
|
||||
int deadBodyHitPoints = EntityClass.list[this.entityClass].DeadBodyHitPoints;
|
||||
if (deadBodyHitPoints > 0 && this.DeathHealth <= -deadBodyHitPoints)
|
||||
{
|
||||
this.deathUpdateTime = this.timeStayAfterDeath;
|
||||
}
|
||||
|
||||
if (this.deathUpdateTime != this.timeStayAfterDeath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isEntityRemote && !this.markedForUnload)
|
||||
{
|
||||
this.dropCorpseBlock();
|
||||
if (this.particleOnDestroy != null && this.particleOnDestroy.Length > 0)
|
||||
{
|
||||
float lightBrightness = this.world.GetLightBrightness(base.GetBlockPosition());
|
||||
this.world.GetGameManager().SpawnParticleEffectServer(
|
||||
new ParticleEffect(this.particleOnDestroy, this.getHeadPosition(), lightBrightness, Color.white,
|
||||
null, null, false), this.entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector3i dropCorpseBlock()
|
||||
{
|
||||
//Log.Out("EntityAliveV2-dropCorpseBlock START");
|
||||
if (lootContainer != null && lootContainer.IsUserAccessing())
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
if (corpseBlockValue.isair)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
if (rand.RandomFloat > corpseBlockChance)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
var vector3I = World.worldToBlockPos(this.position);
|
||||
while (vector3I.y < 254 && (float)vector3I.y - this.position.y < 3f &&
|
||||
!this.corpseBlockValue.Block.CanPlaceBlockAt(this.world, 0, vector3I, this.corpseBlockValue, false))
|
||||
{
|
||||
vector3I += Vector3i.up;
|
||||
}
|
||||
|
||||
if (vector3I.y >= 254)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
if ((float)vector3I.y - this.position.y >= 2.1f)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
this.world.SetBlockRPC(vector3I, this.corpseBlockValue);
|
||||
|
||||
if (vector3I == Vector3i.zero)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
if (world.GetTileEntity(0, vector3I) is not TileEntityLootContainer tileEntityLootContainer)
|
||||
{
|
||||
return Vector3i.zero;
|
||||
}
|
||||
|
||||
if (lootContainer != null)
|
||||
{
|
||||
tileEntityLootContainer.CopyLootContainerDataFromOther(lootContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
tileEntityLootContainer.lootListName = this.lootListOnDeath;
|
||||
tileEntityLootContainer.SetContainerSize(LootContainer.GetLootContainer(lootListOnDeath).size,
|
||||
true);
|
||||
}
|
||||
|
||||
tileEntityLootContainer.SetModified();
|
||||
return vector3I;
|
||||
}
|
||||
}
|
||||
326
Score/NPCv2/Scripts/Entity/SupportClasses/LeaderUtils.cs
Normal file
326
Score/NPCv2/Scripts/Entity/SupportClasses/LeaderUtils.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
using System.Collections;
|
||||
|
||||
public class LeaderUtils
|
||||
{
|
||||
private EntityAliveV2 _entityAlive;
|
||||
private EntityPlayer _owner;
|
||||
private bool _hasNavObjectsEnabled;
|
||||
private bool _isTeleporting;
|
||||
|
||||
public LeaderUtils(EntityAliveV2 entityAlive)
|
||||
{
|
||||
_entityAlive = entityAlive;
|
||||
}
|
||||
|
||||
public bool IsTeleporting
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isTeleporting;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._isTeleporting = value;
|
||||
}
|
||||
}
|
||||
|
||||
public EntityPlayer Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return _owner;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._owner = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetOwner()
|
||||
{
|
||||
//Log.Out("LeaderUtils-SetOwner START");
|
||||
var flLeader = _entityAlive.Buffs.GetCustomVar("$Leader");
|
||||
|
||||
//Log.Out("LeaderUtils-SetOwner flLeader: " + flLeader);
|
||||
|
||||
_entityAlive.belongsPlayerId = (int)flLeader;
|
||||
|
||||
var player = _entityAlive.world.GetEntity(_entityAlive.belongsPlayerId) as EntityPlayer;
|
||||
if (player)
|
||||
{
|
||||
//Log.Out("LeaderUtils-SetOwner 1");
|
||||
_owner = player;
|
||||
_entityAlive.IsEntityUpdatedInUnloadedChunk = true;
|
||||
_entityAlive.bWillRespawn = true;
|
||||
_entityAlive.bIsChunkObserver = true;
|
||||
|
||||
if (!_hasNavObjectsEnabled)
|
||||
{
|
||||
if (_entityAlive is EntityAliveV2 entityAliveV2)
|
||||
entityAliveV2.HandleNavObject();
|
||||
_hasNavObjectsEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCompanion()
|
||||
{
|
||||
//Log.Out("LeaderUtils-AddCompanion START");
|
||||
|
||||
if (_owner == null)
|
||||
{
|
||||
//Log.Out("LeaderUtils-AddCompanion 1");
|
||||
SetOwner();
|
||||
}
|
||||
|
||||
if (_owner != null)
|
||||
{
|
||||
//Log.Out("LeaderUtils-AddCompanion 2");
|
||||
int num2 = ((EntityPlayer)_owner).Companions.IndexOf(_entityAlive);
|
||||
if (num2 < 0)
|
||||
{
|
||||
((EntityPlayer)_owner).Companions.Add(_entityAlive);
|
||||
}
|
||||
num2 = ((EntityPlayer)_owner).Companions.IndexOf(_entityAlive);
|
||||
var v = Constants.TrackedFriendColors[num2 % Constants.TrackedFriendColors.Length];
|
||||
if (_entityAlive.NavObject != null)
|
||||
{
|
||||
//Log.Out("LeaderUtils-AddCompanion 3");
|
||||
_entityAlive.NavObject.UseOverrideColor = true;
|
||||
_entityAlive.NavObject.OverrideColor = v;
|
||||
_entityAlive.NavObject.name = _entityAlive.EntityName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LeaderUpdate()
|
||||
{
|
||||
if (_entityAlive.IsDead())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_owner == null)
|
||||
{
|
||||
SetOwner();
|
||||
}
|
||||
|
||||
//Log.Out("LeaderUtils-LeaderUpdate CurrentOrder: " + _entityAlive.Buffs.GetCustomVar("CurrentOrder"));
|
||||
//Log.Out("LeaderUtils-LeaderUpdate _entityAlive.emodel.visible: " + _entityAlive.emodel.visible);
|
||||
|
||||
if (_entityAlive.Buffs.GetCustomVar("CurrentOrder") == (int)EntityUtilities.Orders.TempStay)
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate IS TEMP STAY");
|
||||
if (_owner != null)
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate OWNER EXISTS");
|
||||
if (_owner.Spawned && _owner.AttachedToEntity)
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate NOT IN A VEHICLE");
|
||||
_entityAlive.SendOnMission(false);
|
||||
_entityAlive.Buffs.SetCustomVar("CurrentOrder", (int)EntityUtilities.Orders.Follow);
|
||||
RebirthManager.UpdateHireInfo(_entityAlive.entityId, "order", "follow", _entityAlive.position.ToString(), _entityAlive.rotation.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_entityAlive.onGround)
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate IS ON GROUND");
|
||||
_entityAlive.guardPosition = _entityAlive.position;
|
||||
_entityAlive.guardLookPosition = _entityAlive.position + _entityAlive.GetLookVector();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_entityAlive.Buffs.GetCustomVar("CurrentOrder") == (int)EntityUtilities.Orders.Follow
|
||||
)
|
||||
{
|
||||
if (_owner != null)
|
||||
{
|
||||
if (_owner.Spawned)
|
||||
{
|
||||
if (((EntityPlayer)_owner).Companions.IndexOf(_entityAlive) < 0)
|
||||
{
|
||||
AddCompanion();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate OWNER DOES NOT EXIST");
|
||||
if (_entityAlive.IsOnMission())
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate IS NOT ON MISSION");
|
||||
_entityAlive.SendOnMission(false);
|
||||
}
|
||||
|
||||
//Log.Out("LeaderUtils-LeaderUpdate SET TO TEMP STAY");
|
||||
_entityAlive.Buffs.SetCustomVar("CurrentOrder", (int)EntityUtilities.Orders.TempStay);
|
||||
RebirthManager.UpdateHireInfo(_entityAlive.entityId, "order", "stay", _entityAlive.position.ToString(), _entityAlive.rotation.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (_entityAlive.belongsPlayerId > 0 && _owner != null)
|
||||
{
|
||||
if (_owner.AttachedToEntity != null && _entityAlive.IsOnMission() && _entityAlive.Buffs.GetCustomVar("CurrentOrder") == (int)EntityUtilities.Orders.Follow)
|
||||
{
|
||||
//Log.Out("LeaderUtils-LeaderUpdate 1");
|
||||
var _position = _owner.GetPosition();
|
||||
_position.y += 2;
|
||||
_entityAlive.SetPosition(_position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TeleportToPlayer(EntityAlive target, bool randomPosition = false)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_entityAlive.Buffs.GetCustomVar("CurrentOrder") != (int)EntityUtilities.Orders.Follow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.IsInElevator())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var position = _entityAlive.position;
|
||||
if (!(_entityAlive.HasAnyTags(FastTags<TagGroup.Global>.Parse("survivor")) || _entityAlive.HasAnyTags(FastTags<TagGroup.Global>.Parse("ally"))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var target2i = new Vector2(target.position.x, target.position.z);
|
||||
var mine2i = new Vector2(position.x, position.z);
|
||||
var distance = Vector2.Distance(target2i, mine2i);
|
||||
|
||||
if (_isTeleporting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var myPosition = target.position + Vector3.back;
|
||||
var player = target as EntityPlayer;
|
||||
if (player != null)
|
||||
{
|
||||
myPosition = player.GetBreadcrumbPos(3 * _entityAlive.rand.RandomFloat);
|
||||
|
||||
// If my target distance is still way off from the player, teleport randomly. That means the bread crumb isn't accurate
|
||||
var distance2 = Vector3.Distance(myPosition, player.position);
|
||||
if (distance2 > 40f)
|
||||
{
|
||||
randomPosition = true;
|
||||
}
|
||||
|
||||
if (randomPosition)
|
||||
{
|
||||
Vector3 dirV = target.position - position;
|
||||
myPosition = RandomPositionGenerator.CalcPositionInDirection(target, target.position, dirV, 5, 80f);
|
||||
}
|
||||
|
||||
float positionY = player.position.y + 1f;
|
||||
if (player.position.y > position.y)
|
||||
{
|
||||
myPosition.y = positionY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) <= player.position.y)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
positionY = GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) + 1f;
|
||||
}
|
||||
}
|
||||
|
||||
myPosition.y = positionY;
|
||||
}
|
||||
|
||||
_entityAlive.SetRevengeTarget((EntityAlive) null);
|
||||
_entityAlive.attackTarget = (EntityAlive) null;
|
||||
|
||||
_entityAlive.motion = Vector3.zero;
|
||||
_entityAlive.navigator?.clearPath();
|
||||
_entityAlive.moveHelper?.Stop();
|
||||
|
||||
_entityAlive.SetPosition(myPosition);
|
||||
_entityAlive.StartCoroutine(ValidateTeleport(target, randomPosition));
|
||||
}
|
||||
|
||||
public void SetDead()
|
||||
{
|
||||
var owner = EntityUtilities.GetLeaderOrOwner(_entityAlive.entityId) as EntityPlayer;
|
||||
if (owner == null) return;
|
||||
|
||||
_entityAlive.lootDropProb = 0;
|
||||
|
||||
if (owner.Companions.IndexOf(_entityAlive) >= 0)
|
||||
{
|
||||
owner.Companions.Remove(_entityAlive);
|
||||
}
|
||||
|
||||
//Log.Out("LeaderUtils-SetDead 1");
|
||||
GameManager.Instance.DropContentOfLootContainerServer(BlockValue.Air, new Vector3i(_entityAlive.position), _entityAlive.entityId);
|
||||
//EntityUtilities.DropBackpack(_entityAlive);
|
||||
}
|
||||
|
||||
public IEnumerator ValidateTeleport(EntityAlive target, bool randomPosition = false)
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
var position = _entityAlive.position;
|
||||
var y = (int)GameManager.Instance.World.GetHeightAt(position.x, position.z);
|
||||
if (position.y < y)
|
||||
{
|
||||
var myPosition = position;
|
||||
|
||||
var player = target as EntityPlayer;
|
||||
if (player != null)
|
||||
myPosition = player.GetBreadcrumbPos(3 * _entityAlive.rand.RandomFloat);
|
||||
|
||||
if (randomPosition)
|
||||
{
|
||||
Vector3 dirV = target.position - position;
|
||||
myPosition = RandomPositionGenerator.CalcPositionInDirection(target, target.position, dirV, 5, 80f);
|
||||
}
|
||||
|
||||
//// Find the ground.
|
||||
if (player != null)
|
||||
{
|
||||
if (player.position.y > this._entityAlive.position.y)
|
||||
{
|
||||
myPosition.y = player.position.y + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) <= player.position.y)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
myPosition.y = GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) + 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myPosition.y = (int)GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) + 2;
|
||||
}
|
||||
|
||||
myPosition.y = (int)GameManager.Instance.World.GetHeightAt(myPosition.x, myPosition.z) + 2;
|
||||
|
||||
// Find the ground.
|
||||
_entityAlive.motion = Vector3.zero;
|
||||
_entityAlive.navigator?.clearPath();
|
||||
_entityAlive.SetPosition(myPosition);
|
||||
}
|
||||
|
||||
_isTeleporting = false;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
56
Score/NPCv2/Scripts/Entity/SupportClasses/MissionUtils.cs
Normal file
56
Score/NPCv2/Scripts/Entity/SupportClasses/MissionUtils.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
public class MissionUtils
|
||||
{
|
||||
private EntityAliveV2 _entityAlive;
|
||||
|
||||
public MissionUtils(EntityAliveV2 entityAlive)
|
||||
{
|
||||
_entityAlive = entityAlive;
|
||||
}
|
||||
|
||||
public bool IsOnMission()
|
||||
{
|
||||
return _entityAlive.Buffs.GetCustomVar("onMission") == 1f;
|
||||
}
|
||||
|
||||
public void SendOnMission(bool send)
|
||||
{
|
||||
//Log.Out("MissionUtils-SendOnMission send: " + send);
|
||||
if (send)
|
||||
{
|
||||
var enemy = _entityAlive.GetRevengeTarget();
|
||||
if (enemy != null)
|
||||
{
|
||||
_entityAlive.attackTarget = (EntityAlive) null;
|
||||
enemy.attackTarget = (EntityAlive) null;
|
||||
enemy.SetRevengeTarget((EntityAlive) null);
|
||||
enemy.DoRagdoll(new DamageResponse());
|
||||
_entityAlive.SetRevengeTarget((EntityAlive) null);
|
||||
}
|
||||
|
||||
_entityAlive.SetIgnoredByAI(true);
|
||||
|
||||
//_entityAlive.transform.localScale = new Vector3(0, 0, 0);
|
||||
_entityAlive.SetScale(0);
|
||||
_entityAlive.emodel.SetVisible(false, false);
|
||||
_entityAlive.Buffs.SetCustomVar("onMission", 1f);
|
||||
|
||||
if (_entityAlive.NavObject != null)
|
||||
_entityAlive.NavObject.IsActive = false;
|
||||
_entityAlive.DebugNameInfo = "";
|
||||
|
||||
_entityAlive.SetupDebugNameHUD(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//_entityAlive.transform.localScale = _entityAlive.scale;
|
||||
_entityAlive.SetScale(_entityAlive.scale.y);
|
||||
_entityAlive.emodel.SetVisible(true, true);
|
||||
|
||||
_entityAlive.enabled = true;
|
||||
_entityAlive.Buffs.SetCustomVar("onMission", 0f);
|
||||
if (_entityAlive.NavObject != null)
|
||||
_entityAlive.NavObject.IsActive = true;
|
||||
_entityAlive.SetIgnoredByAI(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Score/NPCv2/Scripts/Entity/SupportClasses/NPCQuestUtils.cs
Normal file
13
Score/NPCv2/Scripts/Entity/SupportClasses/NPCQuestUtils.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class NPCQuestUtils
|
||||
{
|
||||
private EntityAlive _entityAlive;
|
||||
public List<Quest> activeQuests;
|
||||
|
||||
|
||||
public NPCQuestUtils(EntityAlive entityAlive)
|
||||
{
|
||||
_entityAlive = entityAlive;
|
||||
}
|
||||
}
|
||||
130
Score/NPCv2/Scripts/Entity/SupportClasses/NPCUtils.cs
Normal file
130
Score/NPCv2/Scripts/Entity/SupportClasses/NPCUtils.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
public class NPCUtils
|
||||
{
|
||||
private EntityAlive _entityAlive;
|
||||
private Transform _largeEntityBlocker;
|
||||
|
||||
private float fallTime;
|
||||
private float fallThresholdTime;
|
||||
|
||||
public NPCUtils(EntityAlive entityAlive)
|
||||
{
|
||||
_entityAlive = entityAlive;
|
||||
_largeEntityBlocker = GameUtils.FindTagInChilds(_entityAlive.RootTransform, "LargeEntityBlocker");
|
||||
}
|
||||
|
||||
public void CheckCollision(float distance = 5f)
|
||||
{
|
||||
var isPlayerWithin = IsAnyPlayerWithingDist(distance, _entityAlive);
|
||||
ToggleCollisions(!isPlayerWithin);
|
||||
}
|
||||
|
||||
public void ToggleCollisions(bool value)
|
||||
{
|
||||
ToggleCollisions(value, _entityAlive);
|
||||
}
|
||||
|
||||
private void ToggleCollisions(bool value, EntityAlive entity)
|
||||
{
|
||||
if (_largeEntityBlocker)
|
||||
{
|
||||
_largeEntityBlocker.gameObject.SetActive(value);
|
||||
}
|
||||
|
||||
entity.PhysicsTransform.gameObject.SetActive(value);
|
||||
entity.IsNoCollisionMode.Value = !value;
|
||||
}
|
||||
|
||||
private static bool IsAnyPlayerWithingDist(float dist, EntityAlive entity)
|
||||
{
|
||||
var persistentPlayerList = GameManager.Instance.GetPersistentPlayerList();
|
||||
if (persistentPlayerList?.Players == null) return false;
|
||||
|
||||
foreach (var keyValuePair in persistentPlayerList.Players)
|
||||
{
|
||||
var entityPlayer = entity.world.GetEntity(keyValuePair.Value.EntityId) as EntityPlayer;
|
||||
|
||||
if (!entityPlayer) continue;
|
||||
|
||||
var magnitude = (entityPlayer.getChestPosition() - entity.position).magnitude;
|
||||
|
||||
if (!entityPlayer || !(magnitude <= dist)) continue;
|
||||
|
||||
return ((EntityAliveV2)entity).IsFriendlyPlayer(entityPlayer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CheckFallAndGround()
|
||||
{
|
||||
if (_entityAlive.isEntityRemote) return;
|
||||
if (!_entityAlive.emodel) return;
|
||||
|
||||
var entityAliveV2 = _entityAlive as EntityAliveV2;
|
||||
var isInElevator = _entityAlive.IsInElevator();
|
||||
|
||||
// Jump state isn't visible, so we made a work around.
|
||||
var jumpState = EntityAlive.JumpState.Off;
|
||||
if (entityAliveV2 != null)
|
||||
{
|
||||
jumpState = entityAliveV2.GetJumpState();
|
||||
}
|
||||
|
||||
var avatarController = _entityAlive.emodel.avatarController;
|
||||
if (!avatarController) return;
|
||||
|
||||
var flag = _entityAlive.onGround || _entityAlive.isSwimming || isInElevator;
|
||||
if (flag)
|
||||
{
|
||||
fallTime = 0f;
|
||||
fallThresholdTime = 0f;
|
||||
if (isInElevator)
|
||||
{
|
||||
fallThresholdTime = 0.6f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fallThresholdTime == 0f)
|
||||
{
|
||||
fallThresholdTime = 0.1f + _entityAlive.rand.RandomFloat * 0.3f;
|
||||
}
|
||||
|
||||
fallTime += 0.05f;
|
||||
}
|
||||
|
||||
var canFall = !_entityAlive.emodel.IsRagdollActive &&
|
||||
_entityAlive.bodyDamage.CurrentStun == EnumEntityStunType.None &&
|
||||
!_entityAlive.isSwimming && !isInElevator && jumpState == EntityAlive.JumpState.Off &&
|
||||
!_entityAlive.IsDead();
|
||||
if (fallTime <= fallThresholdTime)
|
||||
{
|
||||
canFall = false;
|
||||
}
|
||||
|
||||
avatarController.SetFallAndGround(canFall, flag);
|
||||
}
|
||||
|
||||
public Vector3 ConfigureBoundaryBox(Vector3 newSize, Vector3 center)
|
||||
{
|
||||
var component = _entityAlive.gameObject.GetComponent<BoxCollider>();
|
||||
if (!component) return Vector3.zero;
|
||||
|
||||
// Re-adjusting the box collider
|
||||
component.size = newSize;
|
||||
|
||||
var scaledExtent = new Vector3(component.size.x / 2f * _entityAlive.transform.localScale.x,
|
||||
component.size.y / 2f * _entityAlive.transform.localScale.y, component.size.z / 2f * _entityAlive.transform.localScale.z);
|
||||
var vector = new Vector3(component.center.x * _entityAlive.transform.localScale.x,
|
||||
component.center.y * _entityAlive.transform.localScale.y, component.center.z * _entityAlive.transform.localScale.z);
|
||||
_entityAlive.boundingBox = BoundsUtils.BoundsForMinMax(-scaledExtent.x, -scaledExtent.y, -scaledExtent.z, scaledExtent.x,
|
||||
scaledExtent.y, scaledExtent.z);
|
||||
|
||||
_entityAlive.boundingBox.center += vector;
|
||||
|
||||
if (center != Vector3.zero)
|
||||
_entityAlive.boundingBox.center = center;
|
||||
return scaledExtent;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
public class PushOutOfBlocksUtils
|
||||
{
|
||||
private EntityAlive _entityAlive;
|
||||
|
||||
public PushOutOfBlocksUtils(EntityAlive entityAlive)
|
||||
{
|
||||
_entityAlive = entityAlive;
|
||||
}
|
||||
private bool ShouldPushOutOfBlock(int _x, int _y, int _z, bool pushOutOfTerrain)
|
||||
{
|
||||
var shape = _entityAlive.world.GetBlock(_x, _y, _z).Block.shape;
|
||||
if (shape.IsSolidSpace && !shape.IsTerrain())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pushOutOfTerrain || !shape.IsSolidSpace || !shape.IsTerrain()) return false;
|
||||
var shape2 = _entityAlive.world.GetBlock(_x, _y + 1, _z).Block.shape;
|
||||
return shape2.IsSolidSpace && shape2.IsTerrain();
|
||||
}
|
||||
|
||||
private bool PushOutOfBlocks(float _x, float _y, float _z)
|
||||
{
|
||||
var num = Utils.Fastfloor(_x);
|
||||
var num2 = Utils.Fastfloor(_y);
|
||||
var num3 = Utils.Fastfloor(_z);
|
||||
var num4 = _x - (float)num;
|
||||
var num5 = _z - (float)num3;
|
||||
var result = false;
|
||||
if (!this.ShouldPushOutOfBlock(num, num2, num3, false) &&
|
||||
(!this.ShouldPushOutOfBlock(num, num2 + 1, num3, false))) return false;
|
||||
var flag2 = !this.ShouldPushOutOfBlock(num - 1, num2, num3, true) &&
|
||||
!this.ShouldPushOutOfBlock(num - 1, num2 + 1, num3, true);
|
||||
var flag3 = !this.ShouldPushOutOfBlock(num + 1, num2, num3, true) &&
|
||||
!this.ShouldPushOutOfBlock(num + 1, num2 + 1, num3, true);
|
||||
var flag4 = !this.ShouldPushOutOfBlock(num, num2, num3 - 1, true) &&
|
||||
!this.ShouldPushOutOfBlock(num, num2 + 1, num3 - 1, true);
|
||||
var flag5 = !this.ShouldPushOutOfBlock(num, num2, num3 + 1, true) &&
|
||||
!this.ShouldPushOutOfBlock(num, num2 + 1, num3 + 1, true);
|
||||
var b = byte.MaxValue;
|
||||
var num6 = 9999f;
|
||||
if (flag2 && num4 < num6)
|
||||
{
|
||||
num6 = num4;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
if (flag3 && 1.0 - (double)num4 < (double)num6)
|
||||
{
|
||||
num6 = 1f - num4;
|
||||
b = 1;
|
||||
}
|
||||
|
||||
if (flag4 && num5 < num6)
|
||||
{
|
||||
num6 = num5;
|
||||
b = 4;
|
||||
}
|
||||
|
||||
if (flag5 && 1f - num5 < num6)
|
||||
{
|
||||
b = 5;
|
||||
}
|
||||
|
||||
var num7 = 0.1f;
|
||||
switch (b)
|
||||
{
|
||||
case 0:
|
||||
_entityAlive.motion.x = -num7;
|
||||
break;
|
||||
case 1:
|
||||
_entityAlive.motion.x = num7;
|
||||
break;
|
||||
case 4:
|
||||
_entityAlive.motion.z = -num7;
|
||||
break;
|
||||
case 5:
|
||||
_entityAlive.motion.z = num7;
|
||||
break;
|
||||
}
|
||||
|
||||
if (b != 255)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual void CheckStuck(Vector3 position, float width, float depth)
|
||||
{
|
||||
_entityAlive.IsStuck = false;
|
||||
if (_entityAlive.IsFlyMode.Value) return;
|
||||
var num = _entityAlive.boundingBox.min.y + 0.5f;
|
||||
_entityAlive.IsStuck = PushOutOfBlocks(position.x - width * 0.3f, num, position.z + depth * 0.3f);
|
||||
_entityAlive.IsStuck = (PushOutOfBlocks(position.x - width * 0.3f, num, position.z - depth * 0.3f) || _entityAlive.IsStuck);
|
||||
_entityAlive.IsStuck = (PushOutOfBlocks(position.x + width * 0.3f, num, position.z - depth * 0.3f) || _entityAlive.IsStuck);
|
||||
_entityAlive.IsStuck = (PushOutOfBlocks(position.x + width * 0.3f, num, position.z + depth * 0.3f) || _entityAlive.IsStuck);
|
||||
if (_entityAlive.IsStuck) return;
|
||||
|
||||
var x = Utils.Fastfloor(position.x);
|
||||
var num2 = Utils.Fastfloor(num);
|
||||
var z = Utils.Fastfloor(position.z);
|
||||
if (!ShouldPushOutOfBlock(x, num2, z, true) ||
|
||||
!CheckNonSolidVertical(new Vector3i(x, num2 + 1, z), 4, 2)) return;
|
||||
_entityAlive.IsStuck = true;
|
||||
_entityAlive.motion = new Vector3(0f, 1.6f, 0f);
|
||||
Log.Warning($"{_entityAlive.EntityName} ({_entityAlive.entityId}) is stuck. Unsticking.");
|
||||
}
|
||||
|
||||
private bool CheckNonSolidVertical(Vector3i blockPos, int maxY, int verticalSpace)
|
||||
{
|
||||
for (int i = 0; i < maxY; i++)
|
||||
{
|
||||
if (!_entityAlive.world.GetBlock(blockPos.x, blockPos.y + i + 1, blockPos.z).Block.shape.IsSolidSpace)
|
||||
{
|
||||
bool flag = true;
|
||||
for (int j = 1; j < verticalSpace; j++)
|
||||
{
|
||||
if (_entityAlive.world.GetBlock(blockPos.x, blockPos.y + i + 1 + j, blockPos.z).Block.shape.IsSolidSpace)
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
38
Score/NPCv2/Scripts/TileEntity/TileEntityAoE.cs
Normal file
38
Score/NPCv2/Scripts/TileEntity/TileEntityAoE.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
public class TileEntityAoE : TileEntity
|
||||
{
|
||||
public TileEntityAoE(Chunk _chunk) : base(_chunk)
|
||||
{
|
||||
}
|
||||
private TileEntityAoE(TileEntityAoE _other) : base(null)
|
||||
{
|
||||
Debug.Log("Creating new TileEntity");
|
||||
localChunkPos = _other.localChunkPos;
|
||||
}
|
||||
|
||||
public override void CopyFrom(TileEntity _other)
|
||||
{
|
||||
Debug.Log("Copy From TileEntity");
|
||||
localChunkPos = _other.localChunkPos;
|
||||
}
|
||||
public override TileEntityType GetTileEntityType()
|
||||
{
|
||||
return (TileEntityType)RebirthUtilities.TileEntityRebirth.TileEntityAoE;
|
||||
}
|
||||
|
||||
public override void Reset(FastTags<TagGroup.Global> questTags)
|
||||
{
|
||||
Debug.Log("Resetting TileEntity");
|
||||
base.Reset(questTags);
|
||||
setModified();
|
||||
}
|
||||
|
||||
public override bool IsActive(World world)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override TileEntity Clone()
|
||||
{
|
||||
Debug.Log("Cloning TileEntity");
|
||||
return new TileEntityAoE(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user