public void DeathTestReviveLater() { BaseEntity player = new MockEntity(Engine) { Name = "MOCK_PLAYER", Key = "MOCK_KEY" }; long reviveDuration = 10; player.ReviveDuration = new MeNode(reviveDuration); player.RefreshProperties(); player.Kill(); MockTimer timer = (MockTimer)Engine.GetTimer(); for (int i = 0; i < reviveDuration; ++i) { player.Update(); timer.ForceTick(); Assert.AreEqual(true, player.IsDead); } player.Update(); Assert.AreEqual(false, player.IsDead); ResourceInstance hp = player.GetResource(Entity.HP_KEY); Assert.AreEqual(hp.MaxAmount * hp.Modifier, hp.Value); }
public void LogEntity(Entity target) { ResourceInstance hp = target.GetResource(Entity.HP_KEY); string hpBar = Utils.Utility.getBar(hp.Value, hp.MaxAmount); string msg = $"{target.Name} {hpBar}"; Log(msg); }
public virtual void LogHeal(Entity target, Entity source, double amount) { ResourceInstance hp = target.GetResource(Entity.HP_KEY); string hpBar = Utils.Utility.getBar(hp.Value, hp.MaxAmount); string msg = $"{target.Name} {hpBar} [{(amount>0?"+":"")}{amount}:0. {hp.Resource.Name}]"; Log(msg); }
public void LogDamage(Entity target, Entity source, DamageTypeTemplate typeTemplate, double amount, double resisted) { ResourceInstance hp = target.GetResource(Entity.HP_KEY); string hpBar = Utils.Utility.getBar(hp.Value, hp.MaxAmount); //string resist = Utils.Utility.DoubleEq(resisted,0.0)?"": $"({resisted} resisted)"; string msg = $"{target.Name} {hpBar} {(amount < 0 ? "" : "-")}{amount} {typeTemplate.Name} damage"; Log(msg); }
public void AddResource(ResourceTemplate resource) { if (ResourceMap.ContainsKey(resource.Key)) { return; } ResourceInstance resIn = new ResourceInstance(resource, this); ResourceMap.Add(resource.Key, resIn); RefreshProperties(); }
public void AddToResource(string key, double amount) { if (!ResourceMap.ContainsKey(key)) { return; } ResourceInstance res = ResourceMap[key]; Engine.Log().Log($"[{Name}]Generated {amount:0.} {res.Resource.Name}."); res.Add(amount); }
public void LevelTestStatIncreaseAffectsResource() { string stat = "VIT"; MockEntity ent = new MockEntity(Engine); double expected = ent.GetProperty(stat).Value + 1; ResourceInstance hp = ((ResourceInstance)ent.GetProperty(Entity.HP_KEY)); double expectedRes = hp.MaxAmount + 20; ent.AddExp(StartExp); ent.AssignAttributePoint(stat); Assert.AreEqual(expected, ent.GetProperty(stat).Value); Assert.AreEqual(expectedRes, hp.MaxAmount); }
public void DeathTestRevive() { BaseEntity player = new MockEntity(Engine) { Name = "MOCK_PLAYER", Key = "MOCK_KEY" }; player.Kill(); player.Update(); Assert.AreEqual(true, player.IsDead); player.Update(); Assert.AreEqual(false, player.IsDead); ResourceInstance hp = player.GetResource(Entity.HP_KEY); Assert.AreEqual(hp.MaxAmount * hp.Modifier, hp.Value); }
void LoadedUI(GameUI ui, ResourceInstance res, params object[] args) { if (ui.state == UIState.Loading) { ui.Load(); ui.Open(args); } else { if (ui.state == UIState.Unloaded) { } else if (ui.state == UIState.Close) { ui.Load(); } } }
public ResourceInstance LoadPrefabAsync(string path, Action <ResourceInstance> loaded = null) { var resIns = prefabList.Find(item => item.path == path); if (resIns == null) { resIns = new ResourceInstance(path); if (loaded != null) { resIns.OnLoaded += loaded; } prefabList.Add(resIns); StartCoroutine(resIns.StartLoad()); return(resIns); } else { return(resIns); } }
/// <summary> /// Method is done as a cleanup, when a resource is deleted, this method will remove the deleted object from an entityInstance reference property /// </summary> /// <param name="targetResource">Resource to look for in the currentEntityInstance</param> /// <param name="property">Reference property to look in on the currentEntityInstance</param> /// <param name="currentEntityInstance">currentEntityInstance that may contain the targetResource</param> private void SetEntityReferenceToNullOnTargetResourceMatch(ResourceInstance targetResource, ResourceProperty property, ResourceInstance currentEntityInstance) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(property, "property"); ExceptionUtilities.CheckArgumentNotNull(currentEntityInstance, "currentEntityInstance"); ExceptionUtilities.Assert(property.Kind == ResourcePropertyKind.ResourceReference, "Should only be called with reference properties"); string propertyName = property.Name; object propertyValue; if (currentEntityInstance.TryGetValue(propertyName, out propertyValue) && propertyValue == targetResource) { this.pendingChanges.Add(() => currentEntityInstance[propertyName] = null); } }
/// <summary> /// The IUpdatable was leaving around left over references after it a resource was being deleted. This will ensure the reference is removed from collections /// and reference properties /// </summary> /// <param name="targetResource">TargetResource To remove</param> private void DeleteAllReferences(ResourceInstance targetResource) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ResourceSet targetResourceSet = this.GetResourceSet(targetResource.ResourceSetName); ExceptionUtilities.CheckObjectNotNull(targetResourceSet, "Resource set could not be found"); List<ResourceSet> resourceSetsToCheck = this.metadataHelper.ResourceAssociationSets.Where(ras => ras.End1.ResourceSet == targetResourceSet).Select(ras2 => ras2.End2.ResourceSet).ToList(); resourceSetsToCheck.AddRange(this.metadataHelper.ResourceAssociationSets.Where(ras => ras.End2.ResourceSet == targetResourceSet).Select(ras2 => ras2.End1.ResourceSet).ToList()); resourceSetsToCheck = resourceSetsToCheck.Distinct().ToList(); foreach (var resourceSet in resourceSetsToCheck) { IList<ResourceInstance> entitySetList = this.ResourceSetsStorage[resourceSet.Name]; foreach (var currentEntityInstance in entitySetList) { ResourceType currentEntityInstanceType = this.GetResourceTypeInternal(currentEntityInstance); foreach (var referenceProperty in currentEntityInstanceType.GetAllPropertiesLazily().Where(p => p.Kind == ResourcePropertyKind.ResourceReference)) { if (this.metadataHelper.IsKindOf(currentEntityInstanceType, currentEntityInstanceType)) { this.SetEntityReferenceToNullOnTargetResourceMatch(targetResource, referenceProperty, currentEntityInstance); } } foreach (var collectionProperty in currentEntityInstanceType.GetAllPropertiesLazily().Where(p => p.Kind == ResourcePropertyKind.ResourceSetReference)) { this.RemoveResourceFromCollectionOnTargetResourceMatch(targetResource, collectionProperty, currentEntityInstance); } } } }
/// <summary> /// Method is done as a cleanup, when a resource is deleted, this method will remove the deleted object from an entityInstance collection property /// </summary> /// <param name="targetResource">Resource to look for in the currentEntityInstance</param> /// <param name="property">The collection property to remove from</param> /// <param name="currentEntityInstance">currentEntityInstance that may contain the targetResource</param> private void RemoveResourceFromCollectionOnTargetResourceMatch(ResourceInstance targetResource, ResourceProperty property, ResourceInstance currentEntityInstance) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(property, "property"); ExceptionUtilities.CheckArgumentNotNull(currentEntityInstance, "currentEntityInstance"); ExceptionUtilities.Assert(property.Kind == ResourcePropertyKind.ResourceSetReference, "Should only be called with reference properties"); string propertyName = property.Name; object propertyValue; if (!currentEntityInstance.TryGetValue(propertyName, out propertyValue)) { return; } IEnumerable childCollectionObject = propertyValue as IEnumerable; ExceptionUtilities.CheckObjectNotNull(childCollectionObject, "Value of '{0}.{1}' was null or not a collection", currentEntityInstance.ResourceTypeName, propertyName); var removeMethod = childCollectionObject.GetType().GetMethod("Remove"); ExceptionUtilities.CheckObjectNotNull(removeMethod, "Could not find remove method for collection property '{0}.{1}'", currentEntityInstance.ResourceTypeName, propertyName); if (childCollectionObject.Cast<object>().Any(o => o == targetResource)) { this.pendingChanges.Add(() => removeMethod.Invoke(childCollectionObject, new object[] { targetResource })); } }
/// <summary> /// For the given association from source to target, perform the appropriate reversed action /// </summary> /// <param name="source">the source of the association to reverse</param> /// <param name="target">the target of the association to reverse</param> /// <param name="forwardPropertyName">the name of the property from source to target</param> /// <param name="remove">whether or not to remove the reversed association</param> private void SetReverseNavigation(ResourceInstance source, ResourceInstance target, string forwardPropertyName, bool remove) { ResourceType targetType; ResourceType sourceType = this.GetResourceTypeInternal(source); if (target == null) { targetType = sourceType.GetAllPropertiesLazily().Single(p => p.Name == forwardPropertyName).ResourceType; } else { targetType = this.GetResourceTypeInternal(target); } ResourceProperty forwardProperty = sourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == forwardPropertyName); if (forwardProperty != null && forwardProperty.CustomState != null) { // because sourceType could match targetType, we need to make sure we filter out the target property ResourceProperty reverseProperty = targetType.GetAllPropertiesLazily() .SingleOrDefault( p => p != forwardProperty && p.CustomState != null && (string)p.CustomState == (string)forwardProperty.CustomState); if (reverseProperty != null) { bool reference = (reverseProperty.Kind & ResourcePropertyKind.ResourceReference) != 0; if (remove) { if (reference) { this.SetReference_Internal(target, reverseProperty.Name, null, false); } else { this.RemoveReferenceFromCollection_Internal(target, reverseProperty.Name, source, false); } } else { if (reference) { this.SetReference_Internal(target, reverseProperty.Name, source, false); } else { this.AddReferenceToCollection_Internal(target, reverseProperty.Name, source, false); } } } } }
private void RemoveReferenceFromCollection_Internal(ResourceInstance targetResource, string propertyName, ResourceInstance resourceToBeRemoved, bool removeBackReference) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); ExceptionUtilities.CheckArgumentNotNull(resourceToBeRemoved, "resourceToBeRemoved"); var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == targetResource.ResourceTypeName); var property = resourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == propertyName); ExceptionUtilities.CheckObjectNotNull(property, "Could not find resource property '{0}' on resource type '{1}'", propertyName, resourceType.FullName); ExceptionUtilities.Assert(property.Kind == ResourcePropertyKind.ResourceSetReference, "RemoveReferenceFromCollection called on property '{0}' with kind '{1}'", propertyName, property.Kind); var collection = (IEnumerable)targetResource[propertyName]; var removeMethod = collection.GetType().GetMethod("Remove"); ExceptionUtilities.CheckObjectNotNull(removeMethod, "Could not find 'Remove' method on collection of type: " + collection.GetType()); removeMethod.Invoke(collection, new object[] { resourceToBeRemoved }); if (removeBackReference) { this.SetReverseNavigation(targetResource, resourceToBeRemoved, propertyName, true); } }
public ResourceLoadCoroutine(ResourceInstance res) { this.res = res; }
private void SetValue(ResourceInstance instance, string propertyName, object propertyValue) { var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == instance.ResourceTypeName); ResourceProperty property = resourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == propertyName); bool isMultiValue = false; if (property != null) { ExceptionUtilities.Assert(!property.Kind.HasFlag(ResourcePropertyKind.Stream), "SetValue called on stream property '{0}'", propertyName); isMultiValue = property.Kind.HasFlag(ResourcePropertyKind.Collection); } if (isMultiValue) { var enumerable = propertyValue as IEnumerable; ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable"); this.pendingChanges.Add(() => this.SetCollectionPropertyValue(instance, propertyName, enumerable)); } else { this.pendingChanges.Add(() => instance[propertyName] = UpdatableToken.ResolveIfToken(propertyValue)); } }
/// <summary> /// Creates a resource in the given set with the given type /// </summary> /// <param name="containerName">The given set name</param> /// <param name="fullTypeName">The given type name</param> /// <returns>The resource created</returns> public virtual object CreateResource(string containerName, string fullTypeName) { ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName"); ResourceType type = this.metadataHelper.ResourceTypes.SingleOrDefault(t => t.FullName == fullTypeName); ExceptionUtilities.CheckObjectNotNull(type, "Could not find type with name '{0}'", fullTypeName); ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!type.IsAbstract, 400, "Cannot create resource because type '{0}' is abstract.", type.FullName); ResourceInstance instance; if (type.ResourceTypeKind == ResourceTypeKind.ComplexType) { ExceptionUtilities.Assert(containerName == null, "Container name must be null for complex types. Value was '{0}'", containerName); if (type.InstanceType == typeof(ResourceInstance)) { instance = new ResourceInstance(type); } else { ConstructorInfo constructor = type.InstanceType.GetConstructor(new[] { typeof(ResourceType) }); ExceptionUtilities.CheckObjectNotNull(constructor, "Could not find constructor for complex type '{0}'", type.InstanceType); instance = (ResourceInstance)constructor.Invoke(new object[] { type }); } } else { ExceptionUtilities.CheckArgumentNotNull(containerName, "containerName"); ResourceSet set = this.GetResourceSet(containerName); ExceptionUtilities.CheckObjectNotNull(set, "Could not find resource set with name '{0}'", containerName); ExceptionUtilities.Assert(set.ResourceType == type || this.GetDerivedTypesInternal(set.ResourceType).Contains(type), "An entity of type '{0}' cannot be added to set '{1}'", fullTypeName, containerName); if (type.InstanceType == typeof(ResourceInstance)) { instance = new ResourceInstance(type, set); } else { ConstructorInfo constructor = type.InstanceType.GetConstructor(new[] { typeof(ResourceType), typeof(ResourceSet) }); ExceptionUtilities.CheckObjectNotNull(constructor, "Could not find constructor for entity type '{0}'", type.InstanceType); instance = (ResourceInstance)constructor.Invoke(new object[] { type, set }); } // TODO: better message ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!this.ResourceSetsStorage[set.Name].Any(e => this.AreKeysEqual(e, instance)), 500, "Duplicate key"); this.pendingChanges.Add(() => this.ResourceSetsStorage[set.Name].Add(instance)); } var token = new UpdatableToken(instance); // foreach property marked as being server generated foreach (ResourceProperty property in type.GetAllPropertiesLazily()) { string propertyName = property.Name; object generatedValue; if (this.TryGetStoreGeneratedValue(containerName, fullTypeName, propertyName, out generatedValue)) { token.PendingPropertyUpdates[propertyName] = generatedValue; this.pendingChanges.Add(() => instance[propertyName] = generatedValue); } } this.InitializeCollectionProperties(type, instance, token, p => p.Kind == ResourcePropertyKind.ResourceSetReference || p.Kind == ResourcePropertyKind.Collection); return token; }
private void InitializeCollectionProperties(ResourceType type, ResourceInstance instance, UpdatableToken token, Func<ResourceProperty, bool> filter) { foreach (ResourceProperty property in type.GetAllPropertiesLazily().Where(filter)) { string propertyName = property.Name; Type collectionType = this.GetCollectionPropertyType(type.FullName, propertyName); if (collectionType != null) { var newCollection = Activator.CreateInstance(collectionType); token.PendingPropertyUpdates[propertyName] = newCollection; this.pendingChanges.Add(() => instance[propertyName] = newCollection); } } }
/// <summary> /// Returns whether two instances have equivalent keys /// </summary> /// <param name="instance1">The first instance to compare</param> /// <param name="instance2">The second instance to compare</param> /// <returns>True if the keys are equal, otherwise false</returns> private bool AreKeysEqual(ResourceInstance instance1, ResourceInstance instance2) { ExceptionUtilities.CheckArgumentNotNull(instance1, "instance1"); ExceptionUtilities.CheckArgumentNotNull(instance2, "instance2"); ExceptionUtilities.Assert(instance1.IsEntityType, "Key equality check only supported on entities"); ExceptionUtilities.Assert(instance2.IsEntityType, "Key equality check only supported on entities"); if (instance1.ResourceSetName != instance2.ResourceSetName) { return false; } var type1 = this.metadataHelper.ResourceTypes.Single(t => t.FullName == instance1.ResourceTypeName); var type2 = this.metadataHelper.ResourceTypes.Single(t => t.FullName == instance2.ResourceTypeName); if (!type1.KeyProperties.SequenceEqual(type2.KeyProperties)) { return false; } foreach (var keyProperty in type1.KeyProperties) { var value1 = instance1.Where(pair => pair.Key == keyProperty.Name).Select(pair => pair.Value).SingleOrDefault(); var value2 = instance2.Where(pair => pair.Key == keyProperty.Name).Select(pair => pair.Value).SingleOrDefault(); if (!ResourceInstance.ArePropertyValuesEqual(value1, value2)) { return false; } } return true; }
/// <summary> /// Sets the value of a collection property /// </summary> /// <param name="targetResource">The resource to set the value on</param> /// <param name="propertyName">The property to set</param> /// <param name="propertyValue">The collection value</param> protected virtual void SetCollectionPropertyValue(ResourceInstance targetResource, string propertyName, IEnumerable propertyValue) { Type collectionType = this.GetCollectionPropertyType(targetResource.ResourceTypeName, propertyName); if (collectionType == null) { targetResource[propertyName] = propertyValue; return; } // need to go through the enumerable and resolve any tokens propertyValue = propertyValue.Cast<object>().Select(o => UpdatableToken.ResolveIfToken(o)); object collection; var enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) }); if (enumerableConstructor != null) { collection = enumerableConstructor.Invoke(new object[] { propertyValue }); } else if (collectionType.IsGenericType && collectionType.GetGenericArguments().Count() == 1) { var typeArgument = collectionType.GetGenericArguments().Single(); var typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable<>).MakeGenericType(typeArgument) }); if (typedEnumerableConstructor != null) { var typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(typeArgument).Invoke(null, new object[] { propertyValue }); collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable }); } else { var typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument }); ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName); collection = Activator.CreateInstance(collectionType); foreach (var element in propertyValue) { typedAddMethod.Invoke(collection, new object[] { element }); } } } else { var addMethod = collectionType.GetMethod("Add"); ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName); collection = Activator.CreateInstance(collectionType); foreach (var element in propertyValue) { addMethod.Invoke(collection, new object[] { element }); } } targetResource[propertyName] = collection; }
private void SetReference_Internal(ResourceInstance targetResource, string propertyName, ResourceInstance propertyValue, bool setBackReference) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == targetResource.ResourceTypeName); var property = resourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == propertyName); ExceptionUtilities.CheckObjectNotNull(property, "Could not find resource property '{0}' on resource type '{1}'", propertyName, resourceType.FullName); ExceptionUtilities.Assert(property.Kind == ResourcePropertyKind.ResourceReference, "SetReference called on property '{0}' with kind '{1}'", propertyName, property.Kind); object oldValue; if (!targetResource.TryGetValue(propertyName, out oldValue)) { oldValue = null; } targetResource[propertyName] = propertyValue; if (setBackReference) { if (propertyValue == null) { propertyValue = (ResourceInstance)oldValue; } if (propertyValue != null) { this.SetReverseNavigation(targetResource, propertyValue, propertyName, (propertyValue == null)); } } }
private void AddReferenceToCollection_Internal(ResourceInstance targetResource, string propertyName, ResourceInstance resourceToBeAdded, bool addBackReference) { ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource"); ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName"); ExceptionUtilities.CheckArgumentNotNull(resourceToBeAdded, "resourceToBeAdded"); var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == targetResource.ResourceTypeName); var property = resourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == propertyName); ExceptionUtilities.CheckObjectNotNull(property, "Could not find resource property '{0}' on resource type '{1}'", propertyName, resourceType.FullName); ExceptionUtilities.Assert(property.Kind == ResourcePropertyKind.ResourceSetReference, "AddReferenceToCollection called on property '{0}' with kind '{1}'", propertyName, property.Kind); object propertyValue; if (!targetResource.TryGetValue(propertyName, out propertyValue)) { Type collectionType = this.GetCollectionPropertyType(targetResource.ResourceTypeName, propertyName); ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not get collection type for '{0}.{1}'", targetResource.ResourceTypeName, propertyName); targetResource[propertyName] = propertyValue = Activator.CreateInstance(collectionType); } // Check to see if item already exists var collection = (IEnumerable)propertyValue; foreach (var existingEntity in collection) { if (this.AreKeysEqual(resourceToBeAdded, (ResourceInstance)existingEntity)) { // TODO: throw? return; } } var addMethod = collection.GetType().GetMethod("Add"); ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find 'Add' method on collection of type: " + collection.GetType()); addMethod.Invoke(collection, new object[] { resourceToBeAdded }); if (addBackReference) { this.SetReverseNavigation(targetResource, resourceToBeAdded, propertyName, false); } }
public override bool Cast(Entity target, string skillKey, bool autocast = false) { string tryAlias = Engine.GetSkillManager().GetKeyFromAlias(skillKey); if (tryAlias == null) { tryAlias = skillKey; } SkillInstance skill = Skills.ContainsKey(tryAlias) ? Skills[tryAlias] : null; if (skill == null) { Engine.Log().Log($"[{Name}] You don't have that skill({tryAlias})."); //log that you don't have that skill return(false); } if (skill.CooldownFinishTime != 0) { long seconds = (skill.CooldownFinishTime - Engine.GetTimer().GetNow()) / GameConstants.TickTime; Engine.Log().Log($"[{Name}] {skill.Skill.Name} is on cooldown for {seconds} s."); return(false); } if (!Free) { Engine.Log().Log($"[{Name}] You are busy."); return(false); } if (!ResourceMap.ContainsKey(skill.Values().Cost.Resource.Key)) { Engine.Log().Log($"[{Name}] You don't have \"{skill.Values().Cost.Resource.Name}\"."); return(false); } ResourceInstance res = ResourceMap[skill.Values().Cost.Resource.Key]; double amount = Sanitizer.ReplacePropeties(skill.Values().Cost.Amount, this).Resolve().Value.ToDouble(); if (!res.CanCast(amount)) { Engine.Log().Log($"[{Name}] Not enough {skill.Values().Cost.Resource.Name} for {skill.Skill.Name}."); return(false); } res.Cast(amount); Free = false; CurrentlyCasting = new SkillCastData(skill, target, this, Engine.GetTimer().GetNow()); long time = CurrentlyCasting.CastFinishTime - Engine.GetTimer().GetNow(); if (time >= GameConstants.TickTime * 3) { string type = skill.Skill.Type == SkillType.Cast ? "casting" : "channeling"; string castedFinish = Key.Equals(CurrentlyCasting.Target.Key) ? "" : $" on {CurrentlyCasting.Target.Name}"; Engine.Log() .Log( $"[{Name}] Started {type} {CurrentlyCasting.Skill.Skill.Name}{castedFinish}."); } return(true); }