public void ThrowItem(int character, int item, Position pos) { //UISystem.Message(DescriptionSystem.GetNameWithID(character) + " throws " + DescriptionSystem.GetNameWithID(item) + " at " + pos); UISystem.Message(DescriptionSystem.GetName(character) + " throws " + DescriptionSystem.GetName(item)); if (Util.CurrentFloor.IsTileBlocked(pos)) { UISystem.Message("You can't throw that there!"); return; } int targetCharacter = Util.CurrentFloor.GetCharacter(pos); if (targetCharacter == 0) { Util.CurrentFloor.PlaceItem(pos, item); } else { UISystem.Message("It hits " + DescriptionSystem.GetName(targetCharacter) + "!"); // TODO: actually calulate the modifier for effects of thrown items float modifier = 0.5f; ApplySubstance(targetCharacter, item, modifier); IdentifyItem(item); DecreaseItemCount(character, item); TryDeleteItem(item); } Util.TurnOver(character); }
/// <summary> /// calculates the next step on the fastest path towards entity /// </summary> /// <param name="entity">ID of entity</param> /// <param name="from">current Position</param> /// <returns> Position of next step </returns> public static Position StepTowards(int entity, Position from) { var findable = EntityManager.GetComponent <FindableComponent>(entity); if (findable == null) { // TODO: initialize new FindableComponent instead? Log.Warning(String.Format("Path to {0} could not be found!", DescriptionSystem.GetNameWithID(entity))); return(from); } Position result = from; // it is assumed, that findable is up to date int minDistance = int.MaxValue; foreach (var pos in from.GetNeighbours()) { int distance = findable.DistanceMap[pos.X, pos.Y]; if (distance < minDistance) { minDistance = distance; result = pos; } // if two tiles are the same distance, randomly decide between them // TODO: make even distribution else if (distance == minDistance && Game.Random.Next(0, 2) == 0) { result = pos; } } return(result); }
public void PickUpItem(int character) { Position position = EntityManager.GetComponent <TransformComponent>(character).Position; int pickupItemID = Util.CurrentFloor.GetFirstItem(position); if (pickupItemID == 0) { UISystem.Message("Nothing here to be picked up!"); return; } bool success = AddItem(character, pickupItemID); if (!success) { return; } // post message to player UISystem.Message(DescriptionSystem.GetNameWithID(character) + " picked up " + DescriptionSystem.GetNameWithID(pickupItemID)); Util.CurrentFloor.RemoveItem(position, pickupItemID); Util.TurnOver(character); }
public void UseItem(int character, int item, ItemUsage usage) { var usableItem = EntityManager.GetComponent <UsableItemComponent>(item); if (usableItem == null) { UISystem.Message("You can't use that!"); return; } if (!usableItem.Usages.Contains(usage)) { UISystem.Message("You can't use that like that!"); return; } UISystem.Message(DescriptionSystem.GetNameWithID(character) + " uses " + DescriptionSystem.GetNameWithID(item) + " -> " + usage); switch (usage) { case ItemUsage.Consume: ConsumeItem(character, item); break; case ItemUsage.Throw: // TODO: throwing range InputManager.Instance.InitiateTargeting((pos) => ThrowItem(character, item, pos)); break; } }
void HandleAttackMessage(int attacker, int defender, Dictionary <DamageType, int> damages) { var posAttacker = EntityManager.GetComponent <TransformComponent>(attacker).Position; var posDefender = EntityManager.GetComponent <TransformComponent>(defender).Position; var seenPositions = Util.CurrentFloor.GetSeenPositions(); bool attackerVisible = seenPositions.Contains(posAttacker); bool defenderVisible = seenPositions.Contains(posDefender); if (!(attackerVisible || defenderVisible)) { return; } StringBuilder sb = new StringBuilder(); if (attackerVisible) { sb.Append(DescriptionSystem.GetName(attacker)); } else { sb.Append("Something"); } sb.Append(" attacks "); if (defenderVisible) { sb.Append(DescriptionSystem.GetName(defender)); } else { sb.Append("Something"); } sb.Append("!"); // e.g. "(69 fire, 42 water, ...)" sb.Append(" ("); for (int i = 0; i < damages.Count; i++) { if (i > 0) { sb.Append(", "); } sb.AppendFormat("{0} {1}", damages.ElementAt(i).Value, damages.ElementAt(i).Key); } sb.Append(")"); UISystem.Message(sb.ToString()); }
public List <string> GetIngredientNames() { List <string> names = new List <string>(); foreach (var item in items) { names.Add(DescriptionSystem.GetName(item)); } return(names); }
public void ConsumeItem(int character, int item) { UISystem.Message(String.Format("{0} consumes {1}", DescriptionSystem.GetNameWithID(character), DescriptionSystem.GetNameWithID(item))); ApplySubstance(character, item, 1f); IdentifyItem(item); DecreaseItemCount(character, item); TryDeleteItem(item); Util.TurnOver(character); }
/// <summary> /// Removes item from charachter inventory /// </summary> /// <param name="item">ID of item</param> /// <param name="character">ID of character</param> public static void RemoveFromInventory(int item, int character) { var inventory = EntityManager.GetComponent <InventoryComponent>(character); if (inventory == null) { Log.Error("Could not remove " + DescriptionSystem.GetNameWithID(item) + " from inventory!"); Log.Error(DescriptionSystem.GetNameWithID(character) + " has no inventory!"); return; } inventory.Items.Remove(item); }
public void ChangeStat(int entity, Stat stat, int amount, int duration) { var stats = EntityManager.GetComponent <StatComponent>(entity); if (stats == null) { Log.Warning("This entity doesn't have stats!"); return; } var baseStats = stats.Values; if (duration < 0) { Log.Warning("Stat modification duration can't be smaller than zero!"); return; } if (duration == 0) // permanent! { baseStats[stat] += amount; UISystem.Message("Some attributes of " + DescriptionSystem.GetName(entity) + " have changed! (permanent)"); return; } // add modifications to stats and add to dict for tracking baseStats[stat] += amount; var mod = new StatModification(stat, amount, duration + 1); // add one to duration to compensate for turn of use modifications.TryGetValue(entity, out List <StatModification> modsOfEntity); if (modsOfEntity == null) { //Console.WriteLine("No mod list for this entiy yet"); modsOfEntity = new List <StatModification>() { mod }; modifications.Add(entity, modsOfEntity); } else { modsOfEntity.Add(mod); } UISystem.Message("Some attributes of " + DescriptionSystem.GetName(entity) + " have changed! (" + duration + " turns)"); }
public void HandleLostHealth(int entity, float amountLost) { var healthComponent = EntityManager.GetComponent <HealthComponent>(entity); healthComponent.Amount -= amountLost; // ded if (healthComponent.Amount <= 0) { UISystem.Message(DescriptionSystem.GetNameWithID(entity) + " dies!"); Util.CurrentFloor.RemoveCharacter(LocationSystem.GetPosition(entity)); EntityManager.RemoveEntity(entity); // mark entity for deletion } //Log.Message("Entity " + entity + " HP: " + healthComponent.Amount + "|" + healthComponent.Max + " (-" + amountLost + ")"); }
/// <summary> /// Crafts an item from the added ingredients /// </summary> /// <returns>true if item was succesfully created</returns> public bool CraftItem() { if (items.Count < 2) { UISystem.Message("You need to put in at least two items!"); ResetCrafting(); return(false); } ExtractSubstances(); // TODO: other crafting than alchemy int newItem = Alchemy(); if (newItem == 0) { // something went wrong before and // should have already been handled ResetCrafting(); return(false); } UISystem.Message("You just crafted something!"); substances.Clear(); foreach (var itemID in items) { ItemSystem.TryDeleteItem(itemID); } items.Clear(); //var description = EntityManager.GetComponent<DescriptionComponent>(newItem); //description.Name = "Crafted " + description.Name; ItemAddedEvent?.Invoke(Util.PlayerID, newItem); string info = DescriptionSystem.GetDebugInfoEntity(newItem); Log.Message("Crafting successful:"); Log.Data(info); Util.TurnOver(Util.PlayerID); return(true); }
public void TurnOver(int entity) { modifications.TryGetValue(entity, out List <StatModification> modsOfEntity); if (modsOfEntity == null) { return; } // unless the entity got its stat component removed this should never be null var statsOfEntity = EntityManager.GetComponent <StatComponent>(entity); var stats = statsOfEntity.Values; bool effectRemoved = false; List <StatModification> toBeRemoved = new List <StatModification>(); for (int i = 0; i < modsOfEntity.Count; i++) { var mod = modsOfEntity[i]; mod.Duration -= 1; //Console.WriteLine(mod.Duration + " left"); if (mod.Duration == 0) { // reverse modification and mark for removal stats[mod.Stat] -= mod.Amount; toBeRemoved.Add(mod); effectRemoved = true; } } foreach (var mod in toBeRemoved) { modsOfEntity.Remove(mod); } if (effectRemoved) { UISystem.Message("Some attributes of " + DescriptionSystem.GetName(entity) + " return to normal."); } }
public bool HandleInteraction(int actor, int other) { var interactable = EntityManager.GetComponent <InteractableComponent>(other); if (interactable == null) { Log.Error("HandleInteraction called on non-interactable object!"); Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); return(false); } //Log.Message("Interaction between " + DescriptionSystem.GetNameWithID(actor) + " and " + DescriptionSystem.GetNameWithID(other)); //Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); if (interactable.ChangeSolidity) { var collider = EntityManager.GetComponent <ColliderComponent>(other); if (collider == null) { Log.Warning("Interactable has ChangeSolidity set but has no collider attached! " + DescriptionSystem.GetNameWithID(other)); Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); } else if (collider.Solid == false) { //TODO: make it solid again? ( ._.)? } else { collider.Solid = false; } } if (interactable.ChangeTexture) { var renderable = EntityManager.GetComponent <RenderableSpriteComponent>(other); if (renderable == null) { Log.Error("Interactable has ChangeTexture set but does not have RenderableSprite attached! " + DescriptionSystem.GetNameWithID(other)); Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); return(false); } if (interactable.AlternateTexture == "") { Log.Warning("Interactable has ChangeTexture set but does not define AlternateTexture! " + DescriptionSystem.GetNameWithID(other)); Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); renderable.Texture = "square"; // placholder; something's not right } else { renderable.Texture = interactable.AlternateTexture; } } if (interactable.GrantsItems) { if (interactable.Items == null) { Log.Warning("Interactable has GrantItems set but does not define Items! " + DescriptionSystem.GetNameWithID(other)); Log.Data(DescriptionSystem.GetDebugInfoEntity(other)); } else if (interactable.Items.Count == 0) { UISystem.Message("Nothing here to be picked up!"); return(false); } else { var inventory = EntityManager.GetComponent <InventoryComponent>(actor); if (inventory == null) { Log.Warning("Pick up failed. Character has no inventory! " + DescriptionSystem.GetNameWithID(actor)); return(false); } else { if (ItemAddedEvent == null) { Log.Error("InteractionSystem->ItemAddedEvent is null!"); return(false); } bool success = ItemAddedEvent.Invoke(actor, interactable.Items[0]); if (success) { interactable.Items.RemoveAt(0); } else { // Failed to add to inventory (should already be handled) return(false); } } } } Util.TurnOver(actor); return(true); }
/// <summary> /// tries to add an item to the character's inventory /// </summary> /// <param name="character"></param> /// <param name="item"></param> /// <returns>true on success</returns> public bool AddItem(int character, int item) { var inventory = EntityManager.GetComponent <InventoryComponent>(character); if (inventory == null) { Log.Warning("Character does not have an inventory! -> " + DescriptionSystem.GetNameWithID(character)); return(false); } var itemInfo = EntityManager.GetComponent <ItemComponent>(item); if (itemInfo == null) { Log.Error("Trying to add item entity to character that's not an item!"); Log.Data(DescriptionSystem.GetDescription(item)); return(false); } if (itemInfo.Count == 0) // happens if item comes back from e.g. crafting reset { itemInfo.Count = 1; } // "Re-Stacking" - item gets handed back from e.g. crafting reset if (inventory.Items.Contains(item)) { itemInfo.Count++; return(true); } #region ItemStacking IEnumerable <IComponent> newItem = EntityManager.GetComponents(item); foreach (var inventoryItemID in inventory.Items) { var inventoryItem = EntityManager.GetComponents(inventoryItemID); bool itemMatch = true; foreach (var newItemComponent in newItem) { bool componentMatch = false; if (newItemComponent.TypeID == Component <TransformComponent> .TypeID) { continue; } foreach (var inventoryItemComponent in inventoryItem) { if (newItemComponent.Equals(inventoryItemComponent)) { componentMatch = true; break; } } if (!componentMatch) { itemMatch = false; break; } } if (itemMatch == true) { var invItemInfo = EntityManager.GetComponent <ItemComponent>(inventoryItemID); int newCount = invItemInfo.Count + itemInfo.Count; invItemInfo.Count = Math.Min(newCount, invItemInfo.MaxCount); int itemsLeft = Math.Max(0, newCount - invItemInfo.MaxCount); // TODO: implement overflow if (itemsLeft > 0) { UISystem.Message(String.Format("{0} x{1} was lost in the void...", DescriptionSystem.GetName(item), itemsLeft)); } EntityManager.RemoveEntity(item); return(true); } } // at this point, no matching item was found if (inventory.Full) { UISystem.Message("Inventory is full! -> " + DescriptionSystem.GetNameWithID(character)); return(false); } inventory.Items.Add(item); return(true); #endregion /* * var pickupComponentTypeIDs = EntityManager.GetComponentTypeIDs(item); * * bool match = false; // can item can be stacked here * * // start looking through every item in inventory * // to find out if picked up item can be stacked * foreach (var invItemID in inventory.Items) * { * var invItemInfo = EntityManager.GetComponent<ItemComponent>(invItemID); * * // if already stacked to max, jump straight to next * if (invItemInfo.Count == invItemInfo.MaxCount) * { * match = false; * continue; * } * * var invItemComponentIDs = EntityManager.GetComponentTypeIDs(invItemID); * * // check if both items have the exact same components attached * match = invItemComponentIDs.All(pickupComponentTypeIDs.Contains) && invItemComponentIDs.Count() == pickupComponentTypeIDs.Count(); * * if (match) * { * var pickedUpItemInfo = EntityManager.GetComponent<ItemComponent>(item); * * // cumulative count doesnt exceed max -> just increase count * // in inventory and remove picked up item * if (invItemInfo.Count + pickedUpItemInfo.Count <= invItemInfo.MaxCount) * { * invItemInfo.Count += pickedUpItemInfo.Count; * EntityManager.RemoveEntity(item); * } * * // cumulative count exceeds max -> * // stack up to max, rest becomes new stack * else * { * pickedUpItemInfo.Count -= invItemInfo.MaxCount - invItemInfo.Count; // remove difference used to max out inventory item * invItemInfo.Count = invItemInfo.MaxCount; * inventory.Items.Add(item); * } * break; * } * } */ //if (!match) //{ //} }
/// <summary> /// sets item properties to known /// </summary> /// <param name="item">ID of item</param> public static void IdentifyItem(int item) { var substance = EntityManager.GetComponent <SubstanceComponent>(item); if (substance == null) { Log.Warning(String.Format("ItemSystem.IdentifyItem: {0} doesn't have SubstanceComponent attached!", DescriptionSystem.GetNameWithID(item))); return; } substance.PropertiesKnown = true; }
public void HandleBasicAttack(int attacker, int defender) { var weapon = GetEquippedWeapon(attacker); List <DamageRange> weaponDamages = new List <DamageRange>(); List <StatScaling> weaponScalings = new List <StatScaling>(); if (weapon != null) { weaponDamages = weapon.Damages; weaponScalings = weapon.Scalings; } if (weaponDamages.Count == 0) { weaponDamages.Add(defaultDamage); } //Log.Data("Damages pre mitigation:\n" + Util.GetStringFromEnumerable(weaponDamages)); // group together all damages by type and roll damage between min and max Dictionary <DamageType, int> preMitigionDamage = new Dictionary <DamageType, int>(); var attackerStatC = EntityManager.GetComponent <StatComponent>(attacker); Dictionary <Stat, int> attackerStats; if (attackerStatC == null) { attackerStats = defaultStats; } else { attackerStats = attackerStatC.Values; } StringBuilder sb = new StringBuilder(); foreach (var damage in weaponDamages) { int damageValue = Game.Random.Next(damage.Min, damage.Max + 1); sb.AppendLine("Damage pre scaling: " + damageValue); float finalModifier = 1f; foreach (var scaling in weaponScalings) { int statValue = 0; attackerStats.TryGetValue(scaling.Stat, out statValue); float modifier = (statValue - 10) / 10f; modifier = 1f + modifier * scaling.Value; finalModifier *= modifier; } sb.AppendLine("Final Modifier: " + finalModifier); damageValue = (int)Math.Round(damageValue * finalModifier); sb.AppendLine("Damage after scaling: " + damageValue); preMitigionDamage.AddOrIncrease(damage.Type, damageValue); } //Log.Data(sb.ToString()); var finalDamages = GetDamagesAfterMitigation(preMitigionDamage, defender); //Log.Data("Damages after mitigation:\n" + Util.GetStringFromEnumerable(damages)); Log.Message(DescriptionSystem.GetNameWithID(defender) + " gets hit for: " + Util.GetStringFromCollection(finalDamages)); HandleAttackMessage(attacker, defender, finalDamages); foreach (var damage in finalDamages) { // TODO: handle different damage types (separate events?) RaiseHealthLostEvent(defender, damage.Value); } Util.TurnOver(attacker); }
/// <summary> /// checks if moving onto newPos is possible /// and triggers any interaction otherwise /// </summary> /// <param name="entity">ID of entity to move</param> /// <param name="newPos">new Position to move to</param> /// <returns>wether movement is possible</returns> private bool TryMove(int entity, Position newPos) { var floor = Util.CurrentFloor; if (floor.IsOutOfBounds(newPos)) { return(false); } int otherCharacter = floor.GetCharacter(newPos); //check if someone's already there if (otherCharacter != 0 && otherCharacter != entity) { // check if collidable if (EntityManager.GetComponent <ColliderComponent>(otherCharacter) != null) { //TODO: talk to npcs? RaiseBasicAttackEvent(entity, otherCharacter); return(false); } else { Log.Warning("Character without collider:"); Log.Data(DescriptionSystem.GetDebugInfoEntity(otherCharacter)); UISystem.Message("Something seems to be there..."); return(false); } } int structure = floor.GetStructure(newPos); if (structure != 0 && EntityManager.GetComponent <ColliderComponent>(structure) != null) { bool solid = RaiseCollisionEvent(entity, structure); // check if interactable var interactable = EntityManager.GetComponent <InteractableComponent>(structure); // only interact with structures right away if they're solid ("bumping" into them) if (solid) { if (interactable != null) { RaiseInteractionEvent(entity, structure); } return(false); } } int terrain = floor.GetTerrain(newPos); // check if collidable with if (terrain != 0 && EntityManager.GetComponent <ColliderComponent>(terrain) != null) { // check if terrain is solid before possible interaction // this is because solidity might be changed by interaction (e.g. door gets opened) bool solid = RaiseCollisionEvent(entity, terrain); // check if interactable var interactable = EntityManager.GetComponent <InteractableComponent>(terrain); if (interactable != null) { RaiseInteractionEvent(entity, terrain); } // check if terrain is solid if (solid) { return(false); } } //trigger special Message on step on if (entity == Util.PlayerID && terrain != 0) { string message = (DescriptionSystem.GetSpecialMessage(terrain, DescriptionComponent.MessageType.StepOn)); if (message.Length > 0) { UISystem.Message(message); } } return(true); }
/// <summary> /// Updates the distance map of a findable entity /// </summary> /// <param name="entity">ID of entity</param> public static void UpdateDistanceMap(int entity) { var findable = EntityManager.GetComponent <FindableComponent>(entity); if (findable == null) { // TODO: initialize new FindableComponent instead? Log.Warning(String.Format("Could not update DistanceMap of {0}, because no FindableComponent was found!", DescriptionSystem.GetNameWithID(entity))); return; } var curPos = GetPosition(entity); if (curPos == findable.LastKnownPosition) { return; } if (findable.DistanceMap == null) { findable.DistanceMap = new int[Util.CurrentFloor.Width, Util.CurrentFloor.Height]; } Util.FillArray2D(findable.DistanceMap, int.MaxValue); bool[,] visited = new bool[Util.CurrentFloor.Width, Util.CurrentFloor.Height]; Queue <Position> todo = new Queue <Position>(); todo.Enqueue(curPos); visited[curPos.X, curPos.Y] = true; findable.DistanceMap[curPos.X, curPos.Y] = 0; while (todo.Count > 0) { var pos = todo.Dequeue(); //Console.WriteLine(pos.ToString()); foreach (var neighbourPos in pos.GetNeighbours()) { if (!(Util.CurrentFloor.IsOutOfBounds(neighbourPos) || visited[neighbourPos.X, neighbourPos.Y] || !Util.CurrentFloor.IsWalkable(neighbourPos))) { todo.Enqueue(neighbourPos); visited[neighbourPos.X, neighbourPos.Y] = true; findable.DistanceMap[neighbourPos.X, neighbourPos.Y] = findable.DistanceMap[pos.X, pos.Y] + 1; } } } //StringBuilder sb = new StringBuilder(); //for (int y = 0; y < findable.DistanceMap.GetLength(1); y++) //{ // for (int x = 0; x < findable.DistanceMap.GetLength(0); x++) // { // int value = findable.DistanceMap[x, y]; // if(value == int.MaxValue) // { // sb.Append("#####"); // } // else // { // sb.Append(String.Format("{0,4} ", value)); // } // } // sb.AppendLine(); //} //Log.Data("distance:\n" + sb.ToString()); findable.LastKnownPosition = curPos; }
/// <summary> /// tries to find an entity /// </summary> /// <param name="entity">ID of entity</param> /// <returns> Position of entity on current floor or null if not found </returns> public static Position GetPosition(int entity) { var transform = EntityManager.GetComponent <TransformComponent>(entity); if (transform == null) { Log.Error("Could not get Position, no TransformComponent attached! " + DescriptionSystem.GetNameWithID(entity)); return(Position.Zero); } return(transform.Position); }
/// <summary> /// calculates WALKING Distance to entity /// </summary> /// <param name="entity">ID of entity</param> /// <param name="from">current Position</param> /// <returns>distance from "from" to Position of entity</returns> public static int GetDistance(int entity, Position from) { var findable = EntityManager.GetComponent <FindableComponent>(entity); if (findable == null) { // TODO: initialize new FindableComponent instead? Log.Warning(String.Format("Distance to {0} could not be calculated!", DescriptionSystem.GetNameWithID(entity))); return(int.MaxValue); } return(findable.DistanceMap[from.X, from.Y]); }