/// <summary> /// Move an entity /// </summary> /// <param name="entity"></param> /// <param name="destination"></param> public void MoveEntity(Combatant entity, Coord destination) { if (!WalkabilityMap[destination]) { throw new Exception(); } if (EntityMap[entity.Coordinate] == null) { throw new Exception(); } EntityMap[entity.Coordinate].Remove(entity); WalkabilityMap[entity.Coordinate] = EntityMap[entity.Coordinate].IsPassable; // clean up seems not needed //if (!EntityMap[entity.Coordinate].Has<AdventureEntity>()) //{ // EntityMap[entity.Coordinate] = null; //} if (EntityMap[destination] == null) { EntityMap[destination] = new AdventureEntityContainer(); } EntityMap[destination].Add(entity); WalkabilityMap[destination] = EntityMap[destination].IsPassable; entity.Coordinate = destination; entity.FovCoords = CalculateFoV(entity.Coordinate, entity is Mogwai); Adventure.Enqueue(AdventureLog.EntityMoved(entity, destination)); }
/// <summary> /// Add entity to the map /// </summary> /// <param name="entity"></param> /// <param name="x"></param> /// <param name="y"></param> public void AddEntity(AdventureEntity entity, int x, int y) { // can't add an entity to invalid position if (!WalkabilityMap[x, y]) { throw new Exception(); } if (!entity.IsPassable) { WalkabilityMap[x, y] = false; } entity.Map = this; entity.Coordinate = new Coord(x, y); if (EntityMap[x, y] == null) { EntityMap[x, y] = new AdventureEntityContainer(); } EntityMap[x, y].Add(entity); if (entity is Combatant combatant) { // calculate fov combatant.FovCoords = CalculateFoV(entity.Coordinate, entity is Mogwai); } // add entity to list Entities.Add(entity); Adventure.Enqueue(AdventureLog.EntityCreated(entity)); }
/// <summary> /// /// </summary> /// <param name="spellCast"></param> /// <returns></returns> private bool Cast(SpellCast spellCast) { var spell = spellCast.Spell; if (spellCast.Target is Entity target) { // TODO: https://github.com/WorldOfMogwais/WoMNetCore/issues/22 var concentrateRoll = 10; Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Cast, ActivityLog.ActivityState.Init, concentrateRoll, spell))); if (concentrateRoll > 1 && concentrateRoll > spell.Level) { Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Cast, ActivityLog.ActivityState.Success, concentrateRoll, spell))); spell.SpellEffect(this, target); } else { Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Cast, ActivityLog.ActivityState.Fail, concentrateRoll, spell))); } Adventure.Enqueue(AdventureLog.Attacked(this, target)); return(true); } return(false); }
/// <summary> /// /// </summary> /// <param name="entity"></param> public void Loot(AdventureEntity entity) { // only allow mogwais to loot if (!(this is Mogwai.Mogwai mogwai)) { return; } if (entity.LootState == LootState.None || entity.LootState == LootState.Looted) { return; } var activity = ActivityLog.Create(ActivityLog.ActivityType.Loot, ActivityLog.ActivityState.None, new int[] { }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, entity, activity)); if (entity.Treasure != null) { activity = ActivityLog.Create(ActivityLog.ActivityType.Treasure, ActivityLog.ActivityState.Success, new int[] { }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, entity, activity)); mogwai.AddGold(entity.Treasure.Gold); } else { activity = ActivityLog.Create(ActivityLog.ActivityType.Treasure, ActivityLog.ActivityState.Fail, new int[] { }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, entity, activity)); } entity.LootState = LootState.Looted; }
/// <summary> /// /// </summary> /// <param name="damageAmount"></param> /// <param name="damageType"></param> public void Damage(int damageAmount, DamageType damageType) { // no damage return or same for dead entities if (damageAmount <= 0 || IsDead) { return; } var activity = ActivityLog.Create(ActivityLog.ActivityType.Damage, ActivityLog.ActivityState.None, new int[] { damageAmount, (int)damageType }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); CurrentHitPoints -= damageAmount; if (!CanAct) { activity = ActivityLog.Create(ActivityLog.ActivityType.HealthState, ActivityLog.ActivityState.None, new int[] { (int)HealthState }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); } if (IsDead) { activity = ActivityLog.Create(ActivityLog.ActivityType.HealthState, ActivityLog.ActivityState.None, new int[] { (int)HealthState }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); Map.DeadEntity(this); } }
/// <summary> /// /// </summary> /// <param name="weaponAttack"></param> /// <returns></returns> private void Attack(WeaponAttack weaponAttack) { var attackTimes = weaponAttack.ActionType == ActionType.Full ? BaseAttackBonus.Length : 1; var weapon = weaponAttack.Weapon; var target = weaponAttack.Target as Entity; //Console.WriteLine($"{Name}: is attacking {attackTimes} times"); // all attacks are calculated Parallel.For(0, attackTimes, (attackIndex, state) => { // break when target is null or dead, no more attacks on dead monsters. if (target == null || target.IsDead) { state.Break(); } var attackRolls = AttackRolls(attackIndex, weapon.CriticalMinRoll); var attack = AttackRoll(attackRolls, target.ArmorClass, out var criticalCounts); Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Attack, ActivityLog.ActivityState.Init, new int[] { attackIndex, attack, criticalCounts }, weaponAttack))); if (attack > target.ArmorClass || criticalCounts > 0) { var damage = DamageRoll(weapon, Dice); var criticalDamage = 0; if (criticalCounts > 0) { for (var i = 0; i < weapon.CriticalMultiplier - 1; i++) { criticalDamage += DamageRoll(weapon, Dice); } } Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Attack, ActivityLog.ActivityState.Success, new int[] { attackIndex, attack, criticalCounts, damage, criticalDamage, (int)DamageType.Weapon }, weaponAttack))); target.Damage(damage + criticalDamage, DamageType.Weapon); } else { Adventure.Enqueue(AdventureLog.Info(this, target, ActivityLog.Create(ActivityLog.ActivityType.Attack, ActivityLog.ActivityState.Fail, new int[] { attackIndex, attack, criticalCounts }, weaponAttack))); } Adventure.Enqueue(AdventureLog.Attacked(this, target)); }); }
/// <summary> /// Passive level up, includes for example hit point roles. /// </summary> private void LevelUp() { var activity = ActivityLog.Create(ActivityLog.ActivityType.Level, ActivityLog.ActivityState.None, new int[] { CurrentLevel }, null); History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); // level up grant free revive SpecialAction(SpecialType.Reviving); // level up grant free heal SpecialAction(SpecialType.Heal); }
/// <inheritdoc /> public override void AddGold(int gold) { var activity = ActivityLog.Create(ActivityLog.ActivityType.Gold, ActivityLog.ActivityState.None, new int[] { gold }, null); History.Add(LogType.Info, activity); if (Adventure != null) { Adventure.Enqueue(AdventureLog.Info(this, null, activity)); Adventure.AdventureStats[AdventureStats.Gold] = Adventure.AdventureStats[AdventureStats.Gold] + gold; } Wealth.Gold += gold; }
/// <summary> /// /// </summary> /// <param name="entity"></param> public void DeadEntity(Combatant entity) { if (EntityMap[entity.Coordinate] == null) { throw new Exception(); } // dead bodies are passable entity.IsPassable = true; WalkabilityMap[entity.Coordinate] = EntityMap[entity.Coordinate].IsPassable; Adventure.Enqueue(AdventureLog.Died(entity)); }
/// <summary> /// Remove entity from the map /// </summary> /// <param name="entity"></param> public void RemoveEntity(Combatant entity) { if (EntityMap[entity.Coordinate] == null) { throw new Exception(); } if (!entity.IsPassable) { WalkabilityMap[entity.Coordinate] = true; } EntityMap[entity.Coordinate] = null; // remove entity to list Entities.Remove(entity); Adventure.Enqueue(AdventureLog.EntityRemoved(entity)); }
/// <inheritdoc /> public override void AddExp(double exp, Monster.Monster monster = null) { var activity = ActivityLog.Create(ActivityLog.ActivityType.Exp, ActivityLog.ActivityState.None, new int[] { (int)exp }, monster); History.Add(LogType.Info, activity); if (Adventure != null) { Adventure.Enqueue(AdventureLog.Info(this, null, activity)); Adventure.AdventureStats[AdventureStats.Experience] = Adventure.AdventureStats[AdventureStats.Experience] + exp; } Exp += exp; while (Exp >= XpToLevelUp) { CurrentLevel += 1; LevelShifts.Add(_currentShift.Height); LevelUp(); } }
/// <summary> /// /// </summary> /// <param name="healAmount"></param> /// <param name="healType"></param> public void Heal(int healAmount, HealType healType) { var missingHealth = MaxHitPoints - CurrentHitPoints; if (missingHealth <= 0 || healAmount <= 0) { return; } if (missingHealth < healAmount) { healAmount = missingHealth; } var activity = ActivityLog.Create(ActivityLog.ActivityType.Heal, ActivityLog.ActivityState.None, new int[] { healAmount, (int)healType }, null); Mogwai.Mogwai.History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); CurrentHitPoints += healAmount; }
/// <summary> /// /// </summary> /// <param name="classType"></param> private void LevelClass(ClassType classType) { if (!CanLevelClass(out _)) { Log.Warn("Not allowed class leveling action."); return; } var classes = Classes.FirstOrDefault(p => p.ClassType == classType); if (Classes.Count == 0 || classes == null) { Classes.Insert(0, Model.Classes.Classes.GetClasses(classType)); } else if (Classes.Remove(classes)) { Classes.Insert(0, classes); } var classesLevels = Classes.Sum(p => p.ClassLevel); // do the class level up Classes[0].ClassLevelUp(); var dice = Shifts[LevelShifts[classesLevels]].MogwaiDice; // level class now LevelClass(dice); // initial class level if (classesLevels == 0) { AddGold(dice.Roll(Classes[0].WealthDiceRollEvent)); } var activity = ActivityLog.Create(ActivityLog.ActivityType.LevelClass, ActivityLog.ActivityState.None, new int[] { (int)classType }, null); History.Add(LogType.Info, activity); Adventure?.Enqueue(AdventureLog.Info(this, null, activity)); }