protected override string HitsMonsterCombatString(Monster target) { string combatStr = ""; if (!Unique) combatStr = "The "; return combatStr + this.SingleDescription + " " + GetWeaponName() + " at the " + target.SingleDescription + ". It hits."; }
/// <summary> /// Increment time - if we have exceeded the duration, call OnExit() and then mark as finished /// </summary> public override void IncrementTime(Monster target) { currentTicks++; if (currentTicks > GetDuration()) { OnEnd(target); hasEnded = true; } }
public CombatResults AttackMonster(Monster monster) { //The monster always dies Game.Dungeon.KillMonster(monster); string msg = monster.Representation + " was killed!"; Game.MessageQueue.AddMessage(msg); LogFile.Log.LogEntry(msg); return CombatResults.DefenderDied; }
public override CombatResults AttackMonster(Monster monster) { string msg = this.Representation + " attacked " + monster.Representation; LogFile.Log.LogEntryDebug(msg, LogDebugLevel.Medium); //Defender always dies Game.Dungeon.KillMonster(monster); msg = this.Representation + " killed " + monster.Representation + " !"; LogFile.Log.LogEntryDebug(msg, LogDebugLevel.Medium); //Game.MessageQueue.AddMessage(msg); return CombatResults.DefenderDied; }
/// <summary> /// Carries out the end effects on the target /// </summary> public abstract void OnEnd(Monster target);
public double CalculateRangedAttackModifiersOnMonster(Monster target) { var damageModifier = 1.0; //Aiming damageModifier += CalculateAimBonus(); //Enemy moving /*if (target != null && target.TurnsMoving > 0) { damageModifier -= 0.2; }*/ return damageModifier; }
public bool AddMonster(Monster creature, int level, Point location) { //Try to add a creature at the requested location //This may fail due to something else being there or being non-walkable try { Map creatureLevel = levels[level]; //Check square is accessable if (!MapSquareCanBeEntered(level, location)) { LogFile.Log.LogEntryDebug("AddMonster failure: Square not enterable", LogDebugLevel.Low); return false; } //Check square has nothing else on it SquareContents contents = MapSquareContents(level, location); if (contents.monster != null) { LogFile.Log.LogEntryDebug("AddMonster failure: Monster at this square", LogDebugLevel.Low); return false; } if (contents.player != null) { LogFile.Log.LogEntryDebug("AddMonster failure: Player at this square", LogDebugLevel.Low); return false; } //Otherwise OK creature.LocationLevel = level; creature.LocationMap = location; monsters.Add(creature); return true; } catch (Exception ex) { LogFile.Log.LogEntry(String.Format("AddCreature: ") + ex.Message); return false; } }
public CombatResults AttackMonsterRanged(Monster monster, int damage) { var modifiedDamage = (int)Math.Ceiling(CalculateRangedAttackModifiersOnMonster(monster) * damage); string combatResultsMsg = "PvM (ranged) " + monster.Representation + "base " + damage + " modified " + modifiedDamage; LogFile.Log.LogEntryDebug(combatResultsMsg, LogDebugLevel.Medium); CancelStealthDueToAttack(); CancelBoostDueToAttack(); return ApplyDamageToMonster(monster, modifiedDamage, false, false); }
public MonsterCommon(Monster mon, int common) { monster = mon; commonness = common; }
/// <summary> /// Add a monster at a random walkable point in the dungeon /// Queries the dungeon for walkable places /// </summary> /// <param name="monster"></param> private void AddMonsterRandomWalkablePoint(Monster monster, int level) { Dungeon dungeon = Game.Dungeon; Point location; int loops = 0; int maxLoops = 50; do { location = Game.Dungeon.RandomWalkablePointInLevel(level); loops++; } while (!Game.Dungeon.AddMonster(monster, level, location) && loops < maxLoops); if(loops == maxLoops) { LogFile.Log.LogEntryDebug("Failed to place: " + monster.Representation, LogDebugLevel.High); } }
/// <summary> /// Returns a new monster of this type /// </summary> /// <param name="monsterType"></param> /// <returns></returns> private Monster NewMonsterOfType(Monster monsterType) { if (monsterType is Creatures.Bat) return new Creatures.Bat(); if (monsterType is Creatures.BlackUnicorn) return new Creatures.BlackUnicorn(); if (monsterType is Creatures.Bugbear) return new Creatures.Bugbear(); if (monsterType is Creatures.Demon) return new Creatures.Demon(); if (monsterType is Creatures.Drainer) return new Creatures.Drainer(); if (monsterType is Creatures.Faerie) return new Creatures.Faerie(); if (monsterType is Creatures.Ferret) return new Creatures.Ferret(); if (monsterType is Creatures.Ghoul) return new Creatures.Ghoul(); if (monsterType is Creatures.Goblin) return new Creatures.Goblin(); if (monsterType is Creatures.GoblinWitchdoctor) return new Creatures.GoblinWitchdoctor(); if (monsterType is Creatures.Imp) return new Creatures.Imp(); if (monsterType is Creatures.Maleficarum) return new Creatures.Maleficarum(); if (monsterType is Creatures.Meddler) return new Creatures.Meddler(); if (monsterType is Creatures.Necromancer) return new Creatures.Necromancer(); if (monsterType is Creatures.Nymph) return new Creatures.Nymph(); if (monsterType is Creatures.Ogre) return new Creatures.Ogre(); if (monsterType is Creatures.Orc) return new Creatures.Orc(); if (monsterType is Creatures.OrcShaman) return new Creatures.OrcShaman(); if (monsterType is Creatures.Overlord) return new Creatures.Overlord(); if (monsterType is Creatures.Peon) return new Creatures.Peon(); if (monsterType is Creatures.Pixie) return new Creatures.Pixie(); if (monsterType is Creatures.Rat) return new Creatures.Rat(); if (monsterType is Creatures.SkeletalArcher) return new Creatures.SkeletalArcher(); if (monsterType is Creatures.Skeleton) return new Creatures.Skeleton(); if (monsterType is Creatures.Spider) return new Creatures.Spider(); if (monsterType is Creatures.Uruk) return new Creatures.Uruk(); if (monsterType is Creatures.Whipper) return new Creatures.Whipper(); if (monsterType is Creatures.Zombie) return new Creatures.Zombie(); LogFile.Log.LogEntryDebug("Failed to add a creature of type: " + monsterType.SingleDescription, LogDebugLevel.High); return null; }
private Point PlaceMonsterCloseToLocation(int levelNo, Monster monsterToPlace, Point centerLoc, int looseGroupDist) { Point location = new Point(); int innerLoopCount = 0; int outerLoopCount = 0; do { location = Game.Dungeon.RandomWalkablePointInLevel(levelNo); innerLoopCount++; if (Utility.GetDistanceBetween(centerLoc, location) > looseGroupDist && innerLoopCount < 50) continue; outerLoopCount++; } while (!Game.Dungeon.AddMonster(monsterToPlace, levelNo, location) && outerLoopCount < 50); if(outerLoopCount != 50) CheckSpecialMonsterGroups(monsterToPlace, levelNo); return location; }
/// <summary> /// Returns true if the monster resisted /// </summary> /// <param name="monster"></param> /// <returns></returns> protected bool CheckMagicResistance(Monster monster) { Player player = Game.Dungeon.Player; int monsterRes = monster.GetMagicRes(); int magicRoll = Game.Random.Next(player.MagicStat); LogFile.Log.LogEntryDebug("Magic resistance attempt. Res: " + monsterRes + " Roll: " + magicRoll, LogDebugLevel.Medium); if (magicRoll < monsterRes) { //Charm not successful string msg = "The spell energy dissipates around the " + monster.SingleDescription + "."; LogFile.Log.LogEntryDebug("Magic resistance - creature resisted", LogDebugLevel.Medium); Game.MessageQueue.AddMessage(msg); return true; } return false; }
public double CalculateMeleeAttackModifiersOnMonster(Monster target) { var meleeEffect = GetActiveEffects(typeof(PlayerEffects.SpeedBoost)); var meleeMultiplier = 1.0; if (meleeEffect.Count() > 0) { meleeMultiplier = ((PlayerEffects.SpeedBoost)meleeEffect.First()).Level * 0.5 + 1; } return meleeMultiplier; }
public double CalculateDamageModifierForAttacksOnPlayer(Monster target) { var damageModifier = 1.0; var speedEffect = GetActiveEffects(typeof(PlayerEffects.SpeedBoost)); var speedModifier = 1.0; if (speedEffect.Count() > 0) { speedModifier += ((PlayerEffects.SpeedBoost)speedEffect.First()).Level; } if(TurnsMoving > 0) { damageModifier -= 0.2 * speedModifier; } if (target != null) { //Test cover var coverItems = GetPlayerCover(target); var hardCover = coverItems.Item1; var softCover = coverItems.Item2; if (hardCover > 0) damageModifier -= 0.5; if (softCover > 0) damageModifier -= 0.1; } return Math.Max(0.0, damageModifier); }
/// <summary> /// Attack a monster with modifiers. Takes care of killing them off if required. /// </summary> /// <param name="monster"></param> /// <returns></returns> public CombatResults AttackMonsterWithModifiers(Monster monster, int hitModifierMod, int damageBaseMod, int damageModifierMod, int enemyACMod, bool specialMoveUsed) { //Do we need to recalculate combat stats? if (this.RecalculateCombatStatsRequired) this.CalculateCombatStats(); if (monster.RecalculateCombatStatsRequired) monster.CalculateCombatStats(); //Attacking a monster with hand to hand give an instrinsic CombatUse = true; //Calculate damage from a normal attack int damage = AttackWithModifiers(monster, hitModifierMod, damageBaseMod, damageModifierMod, enemyACMod); return ApplyDamageToMonster(monster, damage, false, specialMoveUsed); }
public CombatResults AttackMonsterThrown(Monster monster, int damage) { string combatResultsMsg = "PvM (thrown) " + monster.Representation + " = " + damage; LogFile.Log.LogEntryDebug(combatResultsMsg, LogDebugLevel.Medium); CancelStealthDueToAttack(); CancelBoostDueToAttack(); return ApplyDamageToMonster(monster, damage, false, false); }
/// <summary> /// If we have generated a group-bearing monster, add its group /// </summary> /// <param name="monster"></param> /// <param name="levelToPlace"></param> private void CheckSpecialMonsterGroups(Monster monster, int levelToPlace) { int minDistance = 5; //Certain monsters spawn in with groups of their friends if (monster is Creatures.GoblinWitchdoctor) { //Spawn in with a random number of ferrets & goblins int noFerrets = 2 + Game.Random.Next(4); int noGoblins = 1 + Game.Random.Next(3); AddMonstersCloseToMaster(new Creatures.Ferret(), noFerrets, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Goblin(), noGoblins, monster, minDistance, levelToPlace); } else if (monster is Creatures.OrcShaman) { //Spawn in with a random number of orcs & spiders int noOrcs = 2 + Game.Random.Next(3); int noSpiders = 1 + Game.Random.Next(2); AddMonstersCloseToMaster(new Creatures.Orc(), noOrcs, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Spider(), noSpiders, monster, minDistance, levelToPlace); } else if (monster is Creatures.Necromancer) { //Spawn in with a random number of skels & zombs int noSkel = 1 + Game.Random.Next(3); int noZomb = 1 + Game.Random.Next(2); AddMonstersCloseToMaster(new Creatures.Skeleton(), noSkel, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Zombie(), noZomb, monster, minDistance, levelToPlace); } else if (monster is Creatures.Meddler) { //Spawn in with a random number of demons & peons int noDem = 1 + Game.Random.Next(2); int noPeon = 1 + Game.Random.Next(3); AddMonstersCloseToMaster(new Creatures.Demon(), noDem, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Peon(), noPeon, monster, minDistance, levelToPlace); } else if (monster is Creatures.Maleficarum) { //Spawn in with a random number of demons & whippers int noDem = 1 + Game.Random.Next(2); int noWhippers = 1 + Game.Random.Next(2); AddMonstersCloseToMaster(new Creatures.Demon(), noDem, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Whipper(), noWhippers, monster, minDistance, levelToPlace); } else if (monster is Creatures.Overlord) { //Spawn in with a random number of demons, imps and drainers int noDem = 1 + Game.Random.Next(3); int noImp = 1; int noDrainer = 1; AddMonstersCloseToMaster(new Creatures.Demon(), noDem, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Imp(), noImp, monster, minDistance, levelToPlace); AddMonstersCloseToMaster(new Creatures.Drainer(), noDrainer, monster, minDistance, levelToPlace); } }
/// <summary> /// Carries out the start effects on the target. /// </summary> public abstract void OnStart(Monster target);
/// <summary> /// Place a monster on level /// </summary> /// <param name="level"></param> /// <param name="monster"></param> /// <returns></returns> private Point PlaceMonster(int level, Monster monster) { Point location = new Point(); int loopCount = 0; do { location = Game.Dungeon.RandomWalkablePointInLevel(level); loopCount++; } while (!Game.Dungeon.AddMonster(monster, level, location) && loopCount < 1000); if (loopCount < 1000) { CheckSpecialMonsterGroups(monster, level); } else { LogFile.Log.LogEntryDebug("Error: Couldn't place monster", LogDebugLevel.High); } return location; }
/// <summary> /// Carries out the end effects on the target /// </summary> public abstract void OnEnd(Monster target);
/// <summary> /// Place the monster, based on type in an appropriate bucket for adding /// </summary> /// <param name="monster"></param> /// <param name="monstersToPlace"></param> /// <param name="linearPatrol"></param> /// <param name="squarePatrol"></param> private void PlaceMonsterInAppropriateClass(Monster monster, List<Monster> monstersToPlace, List<MonsterFightAndRunAI> linearPatrol, List<MonsterFightAndRunAI> squarePatrol) { if (!(monster is MonsterFightAndRunAI)) { monstersToPlace.Add(monster); return; } MonsterFightAndRunAI monsterAI = monster as MonsterFightAndRunAI; if (monsterAI.GetPatrolType() == PatrolType.Waypoints && monsterAI.HasSquarePatrol()) { squarePatrol.Add(monsterAI); return; } if (monsterAI.GetPatrolType() == PatrolType.Waypoints) { linearPatrol.Add(monsterAI); return; } monstersToPlace.Add(monster); return; }
/// <summary> /// Called every click. If the event duration is over, call OnEnd() and mark as ended /// </summary> public abstract void IncrementTime(Monster target);
/// <summary> /// Add a monster with a random patrol. Needs the mapgenerator of the level in question /// </summary> /// <param name="monster"></param> /// <param name="mapGen"></param> private bool AddMonsterFarFromLocation(Monster monster, Point location, int level, MapGenerator mapGen) { //Offset location int maxLoops = 50; int loops = 0; Point toPlaceLoc = new Point(location); int distance = 40; do { toPlaceLoc = new Point(location.x + (int)Gaussian.BoxMuller(distance, 5), location.y + (int)Gaussian.BoxMuller(distance, 5)); loops++; distance--; } while (!Game.Dungeon.AddMonster(monster, level, toPlaceLoc) && loops < maxLoops); if (loops == maxLoops) { LogFile.Log.LogEntryDebug("Failed to place: " + monster.Representation + " far from to: " + location + " reverting to random placement", LogDebugLevel.Medium); loops = 0; do { toPlaceLoc = Game.Dungeon.RandomWalkablePointInLevel(level); loops++; } while (!Game.Dungeon.AddMonster(monster, level, toPlaceLoc) && loops < maxLoops); LogFile.Log.LogEntryDebug("Failed to place: " + monster.Representation + " giving up", LogDebugLevel.High); return false; } LogFile.Log.LogEntryDebug("Item " + monster.Representation + " placed at: " + location.ToString(), LogDebugLevel.High); return true; }
public virtual CombatResults AttackMonster(Monster monster) { //Recalculate combat stats if required if (this.RecalculateCombatStatsRequired) this.CalculateCombatStats(); if (monster.RecalculateCombatStatsRequired) monster.CalculateCombatStats(); //Set the attacked by marker monster.LastAttackedBy = this; monster.LastAttackedByID = this.UniqueID; //Notify the creature that it has been attacked monster.NotifyAttackByCreature(this); //Wake a sleeping creature if (monster.Sleeping) { monster.WakeCreature(); //All wake on sight creatures should be awake at this point. If it's a non-wake-on-sight tell the player it wakes Game.MessageQueue.AddMessage("The " + monster.SingleDescription + " wakes up!"); LogFile.Log.LogEntryDebug(monster.Representation + " wakes on attack by monster " + this.Representation, LogDebugLevel.Low); } //Calculate damage from a normal attack int damage = AttackCreatureWithModifiers(monster, 0, 0, 0, 0); string messageStr; //Do we hit the monster? if (damage > 0) { //Notify the creature that it has been hit monster.NotifyHitByCreature(this, damage); int monsterOrigHP = monster.Hitpoints; monster.Hitpoints -= damage; //Is the player dead, if so kill it? if (monster.Hitpoints <= 0) { Game.Dungeon.KillMonster(monster, false); //Debug string string combatResultsMsg = "MvM " + this.Representation + " vs " + monster.Representation + " ToHit: " + toHitRoll + " AC: " + monster.ArmourClass() + " Dam: 1d" + damageBase + "+" + damageModifier + " MHP: " + monsterOrigHP + "->" + monster.Hitpoints + " killed"; messageStr = HitsMonsterCombatString(monster) + " It's knocked out."; Game.MessageQueue.AddMessage(messageStr); //Game.MessageQueue.AddMessage(combatResultsMsg); LogFile.Log.LogEntryDebug(combatResultsMsg, LogDebugLevel.Medium); //Add charm XP if appropriate Game.Dungeon.Player.AddXPMonsterAttack(this, monster); return CombatResults.DefenderDied; } //Debug string string combatResultsMsg3 = "MvM " + this.Representation + " vs " + monster.Representation + " ToHit: " + toHitRoll + " AC: " + monster.ArmourClass() + " Dam: 1d" + damageBase + "+" + damageModifier + " MHP: " + monsterOrigHP + "->" + monster.Hitpoints + " injured"; messageStr = HitsMonsterCombatString(monster); Game.MessageQueue.AddMessage(messageStr); LogFile.Log.LogEntryDebug(combatResultsMsg3, LogDebugLevel.Medium); return CombatResults.DefenderDamaged; } //Miss string combatResultsMsg2 = "MvM " + this.Representation + " vs " + monster.Representation + " ToHit: " + toHitRoll + " AC: " + monster.ArmourClass() + " Dam: 1d" + damageBase + "+" + damageModifier + " MHP: " + monster.Hitpoints + " miss"; //Game.MessageQueue.AddMessage(combatResultsMsg2); messageStr = MissesMonsterCombatString(monster); Game.MessageQueue.AddMessage(messageStr); LogFile.Log.LogEntryDebug(combatResultsMsg2, LogDebugLevel.Medium); return CombatResults.DefenderUnhurt; }
/// <summary> /// Add cohort monsters close to a unique. Spawns new copies of the cohort monster type passed in (does not use the passed object) /// </summary> /// <param name="monsterType"></param> /// <param name="noMonsters"></param> /// <param name="masterMonser"></param> /// <param name="minDistance"></param> /// <param name="levelNo"></param> /// <returns></returns> private bool AddMonstersCloseToMaster(Monster monsterType, int noMonsters, Creature masterMonser, int minDistance, int levelNo) { Point location; int outerLoopCount = 0; for (int i = 0; i < noMonsters; i++) { do { int loopCount = 0; do { location = Game.Dungeon.RandomWalkablePointInLevel(i); loopCount++; } while (Utility.GetDistanceBetween(masterMonser, location) > minDistance && loopCount < maxLoopCount); outerLoopCount++; } while (!Game.Dungeon.AddMonster(NewMonsterOfType(monsterType), levelNo, location) && outerLoopCount < 50); } //Failed to add monster if (outerLoopCount == 50) { LogFile.Log.LogEntryDebug("Failed to place a monster near master", LogDebugLevel.Medium); return false; } return true; }
protected abstract string HitsMonsterCombatString(Monster target);
/// <summary> /// Kill a monster. This monster won't get any further turns. /// </summary> /// <param name="monster"></param> public void KillMonster(Monster monster) { //We can't take the monster out of the collection directly since we might still be iterating through them //Instead set a flag on the monster and remove it after all turns are complete monster.Alive = false; }
protected abstract string MissesMonsterCombatString(Monster target);
/// <summary> /// Called every click. If the event duration is over, call OnEnd() and mark as ended /// </summary> public abstract void IncrementTime(Monster target);
public abstract CombatResults AttackMonster(Monster monster);
/// <summary> /// Carries out the start effects on the target. /// </summary> public abstract void OnStart(Monster target);
public MonsterEffect(Monster eventReceiver) : base(eventReceiver) { this.monster = eventReceiver; }