private AttackerTypes GetWeightedAttackerType(bool AllowBoss) { int d = TDMath.D(100); if (d < 25) { return(AttackerTypes.Goblin); } else if (d < 50) { return(AttackerTypes.GoblinArcher); } else if (d < 75) { return(AttackerTypes.Orc); } else if (d < 95 || (AllowBoss == false)) // boss number will default to troll { return(AttackerTypes.Troll); } else // d >= 95 { return(AttackerTypes.Boss); } }
private void HitTarget(TDEntity entity) { #region splash if (this.SplashRadius > 0) { DamageRadius(target.Location, this.SplashRadius); // spawn a new explosion TDSession.thisSession.CurrentLevel.Explosions.Add(new TDExplosion(entity.Location, this.SplashRadius)); } #endregion else // not splash { entity.HPCurrent -= this.damage; // apply any effects if (this.Effects != null && this.Effects.Count > 0) { foreach (TDEffect e in this.Effects) { entity.Effects.Add(new TDEffect(e.Effect, e.Power, e.Duration, true)); } } } #region Chaining if (this.ChainCount > 0) { // find the next closest attacker, not the source List <TDEntity> newTargets = GetTowersInRange(entity.Location, this.ChainDist, false, true); // don't hit this source. if (newTargets.Contains(this.source)) { newTargets.Remove(this.source); } // and don't hit this new target itself if (newTargets.Contains(entity)) { newTargets.Remove(entity); } if (newTargets.Count > 0) { // get a random target within this range TDEntity newTarget = newTargets[TDMath.D(newTargets.Count) - 1]; // make a new ammo from this one, TDAmmo newAmmo = new TDAmmo(entity, newTarget); // start from this target hit // reduce the chain count newAmmo.ChainDist = this.ChainDist; newAmmo.ChainCount = this.ChainCount - 1; newAmmo.damage = Math.Max(1, this.damage - 1); // override the damage with the chain decline TDSession.thisSession.CurrentLevel.Ammo.Add(newAmmo); } } #endregion // since ammo dies automatically this.DeleteMe = true; }
private void GenerateAttackersForLevel(int lvl, List <TDPath> Paths) { // waves this._WaveCount = 9 + (lvl); if (testing) { _WaveCount = 0; } // wave attacker type bool mixed = (TDMath.D(100) > 70); // 30% mixed // attackers per wave int attPerWave = 5 + TDMath.D(10 * lvl); if (testing) { attPerWave = 0; } // if 80, then betwen 41 and 80; int ThisWaveDelay = (WaveDelay / 2) + TDMath.D(WaveDelay / 2); if (testing) { ThisWaveDelay = WaveDelay; } int MaxDelay = 0; // for each wave for (int i = 0; i < this._WaveCount; i++) { // set the type and path for this wave AttackerTypes t = GetWeightedAttackerType(false); TDPath p = Paths[TDMath.D(Paths.Count) - 1]; // vary the attacker separation for this wave (between 1/2 and full value) int AttackerDelayWithinThisWave = (AttackerDelayWithinWave / 2) + TDMath.D((AttackerDelayWithinWave / 2)); if (testing) { AttackerDelayWithinThisWave = AttackerDelayWithinWave; } for (int j = 0; j < attPerWave; j++) { // check for mixed attacker type if (mixed && lvl > 3) // don't mix until lvl 4+ { // randomized the type for the next attacker t = GetWeightedAttackerType(true); p = Paths[TDMath.D(Paths.Count) - 1]; } // generate the new attacker TDAttacker a = new TDAttacker(t, lvl); a.WaveIndex = i + 1; int delayMS = Math.Max(1, (i * ThisWaveDelay) + (j * AttackerDelayWithinThisWave)); // slightly stagger each attacker within the wave (j) a.Effects.Add(new TDEffect(TDEffectTypes.WaveDelay, 0, new TimeSpan(0, 0, 0, 0, delayMS), false)); a.SetPath(p); this.Attackers.Add(a); // remember the MaxDelay for the Boss MaxDelay = Math.Max(MaxDelay, delayMS); } } // and finally, add the level boss TDAttacker boss = new TDAttacker(AttackerTypes.Boss, lvl + 10); boss.Size += 4; boss.HPMax = boss.HPMax * 6; boss.HPCurrent = boss.HPMax; int AdditionalBossDelay = 500; if (testing) { AdditionalBossDelay = 10000; } boss.Effects.Add(new TDEffect(TDEffectTypes.WaveDelay, 0, new TimeSpan(0, 0, 0, 0, MaxDelay + AdditionalBossDelay), false)); // 1/2 second after last attacker TDPath pBoss = Paths[TDMath.D(Paths.Count) - 1]; boss.SetPath(pBoss); this.Attackers.Add(boss); }
public override void Update() { if (this.CanStart && this.Immune) { this.Immune = false; // update the next wave to be at least this index. TDSession.thisSession.CurrentLevel.WaveStarted = Math.Max(this.WaveIndex, TDSession.thisSession.CurrentLevel.WaveStarted); } // apply any effects if (this.Effects != null && this.Effects.Count > 0) { foreach (TDEffect e in this.Effects) { if (e.Effect == TDEffectTypes.WaveDelay) { if (e.State == TDEffect.TDTimerState.Finished) { e.HasBeenApplied = true; this.CanStart = true; } else if (e.State == TDEffect.TDTimerState.Running && e.DurationRemaining.TotalMilliseconds < 0) { e.State = TDEffect.TDTimerState.Finished; return; } else { // if we have not finished this effect, then we can't start yet. (or do anything else). return; } } #region Slow if (e.Effect == TDEffectTypes.Slow) { if (e.State == TDEffect.TDTimerState.Running) { // slow only applies once if (!e.HasBeenApplied) { // change current speed to effect. this.SpeedCurrent = (this.SpeedMax * (100 - (double)e.Power) / 100); e.HasBeenApplied = true; } } else if (e.State == TDEffect.TDTimerState.Finished) { // only edit if the effect is still applied if (e.HasBeenApplied) { // set the speed back to normal this.SpeedCurrent = this.SpeedMax; // tell the system we have undid the speed change e.HasBeenApplied = false; } } } // end slow #endregion } } // next point if (OnPoint(this.Location, this.Path.PathPoints[NextPoint].Location)) { // change destination to the next point on the path. NextPoint++; // if on last point, then damage lvl HP if (NextPoint >= Path.PathPoints.Count) { TDSession.thisSession.CurrentLevel.HPRemaining -= this.HPCurrent; this.Cost = 0; // no loot for an enemy crashing into your base! DeleteMe = true; return; } } // move toward point MoveToward(this.Path.PathPoints[NextPoint].Location); // check cooldown to see if can fire if (DateTime.Now > this.LastFire + new TimeSpan(0, 0, 0, 0, (int)(this.Cooldown.TotalMilliseconds / TDSession.SpeedFactor))) { // we can, so see if any towers in range List <TDTower> towersInRange = GetTowersInRange(); // check towers in range to fire at if (towersInRange.Count == 0) { // do nothing - no towers } else { // only have a chance to shoot this update (makes the firing more random) if (TDMath.D(100) > 97) { if (towersInRange.Count == 1) { // if one is the destination tower, hit it ShootAtTower(towersInRange[0]); } else if (towersInRange.Count > 1) { // if multiples // future: pick a tower (weakest, strongest, first?) // for now, just shoot the first one ShootAtTower(towersInRange[0]); } LastFire = DateTime.Now; } } // end else - are towers in range } }