Upload from upload_mods.ps1

This commit is contained in:
Nathaniel Cosford
2025-06-04 16:44:53 +09:30
commit f1fbbe67bb
1722 changed files with 165268 additions and 0 deletions

View 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;
}
}

View 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;
}
}

View 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);
}
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -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;
}
}