public bool Process() { if (Timer == 0) { Unit.VState = UnitVisualState.Attacking; Unit.AttackFrame = 0; Unit.AttackTime = 0; Unit.DoUpdateView = true; Speed = 0.5f; } if (Unit.Class.AttackPhases > 1) { if (Speed * Unit.AttackTime >= Unit.Class.AttackFrames[Unit.AttackFrame].Time) { //Unit.AttackFrame = ++Unit.AttackFrame % Unit.Class.AttackPhases; Unit.AttackFrame++; if (Unit.AttackFrame >= Unit.Class.AttackPhases) { Unit.AttackFrame = Unit.Class.AttackPhases - 1; } Unit.AttackTime = -1; Unit.DoUpdateView = true; } Unit.AttackTime++; } else { Unit.AttackFrame = 0; Unit.AttackTime = 0; } if (Speed * Timer >= Unit.Charge && !NetworkManager.IsClient && !DamageDone) { // do damage here! // check if we need to fire a projectile (range) AllodsProjectile proj = AllodsProjectile.None; // default :D // check for castspell in weapon. // check for weapon. List <Spell> castspells = new List <Spell>(); bool procoverride = false; if (Unit.GetObjectType() == MapObjectType.Human) { Item weapon = ((MapHuman)Unit).GetItemFromBody(MapUnit.BodySlot.Weapon); // if weapon is a staff, then castspell is called immediately. // otherwise castspell is only applied when the projectile hits. if (weapon != null && weapon.IsValid) { foreach (ItemEffect eff in weapon.Effects) { if (eff.Type1 == ItemEffect.Effects.CastSpell) { Spell sp = new Spell(eff.Value1); sp.Skill = eff.Value2; sp.User = Unit; sp.Item = weapon; castspells.Add(sp); } } if (weapon.Class.Option.Name == "Staff" || weapon.Class.Option.Name == "Shaman Staff") { procoverride = true; } } } if (Unit.Interaction.GetAttackRange() > 1) { // send this projectile to clients too // make projectile specified in the unit class. proj = (AllodsProjectile)Unit.Class.Projectile; } if (!procoverride && Spell == null) { if (proj != AllodsProjectile.None) { // following offsets are based on unit's width, height and center float cX = Unit.X + Unit.Width * 0.5f + Unit.FracX; float cY = Unit.Y + Unit.Height * 0.5f + Unit.FracY; float tX = TargetUnit.X + TargetUnit.Width * 0.5f + TargetUnit.FracX; float tY = TargetUnit.Y + TargetUnit.Height * 0.5f + TargetUnit.FracY; Vector2 dir = new Vector2(tX - cX, tY - cY).normalized *((Unit.Width + Unit.Height) / 2) / 1.5f; cX += dir.x; cY += dir.y; Server.SpawnProjectileDirectional(proj, Unit, cX, cY, 0, tX, tY, 0, 10, (MapProjectile fproj) => { if (fproj.ProjectileX >= TargetUnit.X + TargetUnit.FracX && fproj.ProjectileY >= TargetUnit.Y + TargetUnit.FracY && fproj.ProjectileX < TargetUnit.X + TargetUnit.FracX + TargetUnit.Width && fproj.ProjectileY < TargetUnit.Y + TargetUnit.FracY + TargetUnit.Height) { //Debug.LogFormat("projectile hit!"); // done, make damage if (TargetUnit.TakeDamage(DamageFlags, Unit, Damage) > 0) { TargetUnit.DoUpdateInfo = true; TargetUnit.DoUpdateView = true; } // and cast spell foreach (Spell spell in castspells) { Spells.SpellProc sp = spell.Cast(TargetUnit.X + TargetUnit.Width / 2, TargetUnit.Y + TargetUnit.Height / 2, TargetUnit); if (sp != null) { Unit.AddSpellEffects(sp); } } } fproj.Dispose(); MapLogic.Instance.Objects.Remove(fproj); }); } else { if (TargetUnit.TakeDamage(DamageFlags, Unit, Damage) > 0) { TargetUnit.DoUpdateInfo = true; TargetUnit.DoUpdateView = true; } } } else { // cast spells directly // just do something atm. // todo: check spells that can be only casted on self (distance 0). if (Spell != null) { Spells.SpellProc sp; if (TargetUnit != null) { sp = Spell.Cast(TargetUnit.X + TargetUnit.Width / 2, TargetUnit.Y + TargetUnit.Height / 2, TargetUnit); } else { sp = Spell.Cast(TargetX, TargetY, null); } if (sp != null) { Unit.AddSpellEffects(sp); } } else { foreach (Spell spell in castspells) { Spells.SpellProc sp = spell.Cast(TargetUnit.X + TargetUnit.Width / 2, TargetUnit.Y + TargetUnit.Height / 2, TargetUnit); if (sp != null) { Unit.AddSpellEffects(sp); } } } } DamageDone = true; } if (Speed * Timer >= Unit.Charge + Unit.Relax) { return(false); // end of attack } Timer++; return(true); }
public override bool Process() { if (NetworkManager.IsClient) { return(false); } // 5x5, but remove corners for (int y = TargetY - 2; y <= TargetY + 2; y++) { for (int x = TargetX - 2; x <= TargetX + 2; x++) { // check for corner tiles :) if ((x == TargetX - 2 || x == TargetX + 2) && (y == TargetY - 2 || y == TargetY + 2)) { continue; } if (x < 0 || y < 0 || x >= MapLogic.Instance.Width || y >= MapLogic.Instance.Height) { continue; } // check if there are FIRE effects on this cell, don't spawn fog bool spawnblocked = false; foreach (MapObject mo in MapLogic.Instance.Nodes[x, y].Objects) { if (!(mo is MapProjectile)) { continue; } MapProjectile mp = (MapProjectile)mo; if (mp.Class == null || mp.Class.ID != (int)AllodsProjectile.PoisonCloud) { continue; } // don't remove if on edge of fire wall if (new Vector2(mp.ProjectileX - x + 0.5f, mp.ProjectileY - y + 0.5f).magnitude > 0.8f) { continue; } spawnblocked = true; break; } if (spawnblocked) { continue; } Server.SpawnProjectileEOT(AllodsProjectile.PoisonCloud, Spell.User, x + 0.5f, y + 0.5f, 0, (int)(MapLogic.TICRATE * Spell.GetDuration()), 40, 0, 0, 16, proj => { DamageFlags spdf = SphereToDamageFlags(Spell); // get projectile cells int axFrom = Mathf.Max(0, Mathf.FloorToInt(proj.ProjectileX)); int axTo = Mathf.Min(MapLogic.Instance.Width - 1, Mathf.CeilToInt(proj.ProjectileX)); int ayFrom = Mathf.Max(0, Mathf.FloorToInt(proj.ProjectileY)); int ayTo = Mathf.Min(MapLogic.Instance.Height - 1, Mathf.CeilToInt(proj.ProjectileY)); for (int py = ayFrom; py <= ayTo; py++) { for (int px = axFrom; px <= axTo; px++) { // check how much projectile is on this cell float pdst = 1f - Mathf.Min(1f, new Vector2(px + 0.5f - proj.ProjectileX, py + 0.5f - proj.ProjectileY).magnitude); // 0..1 effect power MapNode node = MapLogic.Instance.Nodes[px, py]; for (int i = 0; i < node.Objects.Count; i++) { MapObject mo = node.Objects[i]; if (!(mo is MapUnit)) { continue; } MapUnit mov = (MapUnit)mo; int dmg = (int)(Spell.GetIndirectPower() * pdst); if (dmg <= 0) { continue; // don't add null effects } SpellEffects.Effect eff = new SpellEffects.Poison(this, dmg, MapLogic.TICRATE * 8); // originally 8 seconds mov.AddSpellEffects(eff); } } } }); } } return(false); }
public override bool Process() { if (NetworkManager.IsClient) { return(false); } // 11x11, but remove corners for (int y = TargetY - 5; y <= TargetY + 5; y++) { for (int x = TargetX - 5; x <= TargetX + 5; x++) { // check for corner tiles :) if (new Vector2(x - TargetX, y - TargetY).magnitude > 5.5f) { continue; } if (x < 0 || y < 0 || x >= MapLogic.Instance.Width || y >= MapLogic.Instance.Height) { continue; } // remove light effects MapNode node = MapLogic.Instance.Nodes[x, y]; for (int i = 0; i < node.Objects.Count; i++) { MapObject mo = node.Objects[i]; if (mo is MapProjectile && ((((MapProjectile)mo).ClassID == AllodsProjectile.SpecDarkness) || (((MapProjectile)mo).ClassID == AllodsProjectile.SpecLight))) { mo.Dispose(); i--; continue; } } float power = Spell.GetScanRange(); int lightlevel = (int)(-(power * 32)); Server.SpawnProjectileEOT(AllodsProjectile.SpecDarkness, Spell.User, x + 0.5f, y + 0.5f, 0, (int)(MapLogic.TICRATE * Spell.GetDuration()), MapLogic.TICRATE / 2, 0, 0, 16, proj => { MapNode pnode = MapLogic.Instance.Nodes[proj.X, proj.Y]; for (int i = 0; i < pnode.Objects.Count; i++) { MapObject mo = pnode.Objects[i]; if (!(mo is MapUnit)) { continue; } MapUnit mov = (MapUnit)mo; // don't affect AI units if (mov.Player == null || mov.Player.DoFullAI) { continue; } SpellEffects.Effect eff = new SpellEffects.Darkness(MapLogic.TICRATE / 2, Spell.GetScanRange()); // 1 second mov.AddSpellEffects(eff); } }, lightlevel); } } return(false); }