private void InitProjectile(int id, IPlayerPawn source, IMapProjectileLogic logic, MapProjectileCallback cb) { ClassID = (AllodsProjectile)id; Class = ProjectileClassLoader.GetProjectileClassById(id); if (Class == null) { // make sure that at least ID is valid if (!Enum.IsDefined(typeof(AllodsProjectile), id)) { // otherwise spam log Debug.LogFormat("Invalid projectile created (id={0})", id); return; } } Source = source; Logic = logic; if (Logic != null) { Logic.SetProjectile(this); } Callback = cb; Width = 1; Height = 1; Alpha = 1f; Color = new Color(1, 1, 1, 1); ZOffset = 128; Scale = 1; DoUpdateView = true; }
private void CreateProjectile(AllodsProjectile proj) { MapProjectile p = new MapProjectile(proj, Unit); p.ZOffset = 64; MapLogic.Instance.AddObject(p, true); Indicators.Add(p); }
// this should only be called for arrows (i.e. homing projectiles), with TargetUnit set. protected void SpawnProjectile(AllodsProjectile type, int speed, int damage) { // following offsets are based on unit's width, height and center float tX, tY; if (TargetUnit != null) { tX = TargetUnit.X + TargetUnit.Width * 0.5f + TargetUnit.FracX; tY = TargetUnit.Y + TargetUnit.Height * 0.5f + TargetUnit.FracY; } else { tX = TargetX + 0.5f; tY = TargetY + 0.5f; } float cX, cY; if (Spell.User != null) { cX = Spell.User.X + Spell.User.Width * 0.5f + Spell.User.FracX; cY = Spell.User.Y + Spell.User.Height * 0.5f + Spell.User.FracY; Vector2 dir = new Vector2(tX - cX, tY - cY).normalized *((Spell.User.Width + Spell.User.Height) / 2) / 1.5f; cX += dir.x; cY += dir.y; } else { cX = tX; cY = tY; } Server.SpawnProjectileHoming(type, Spell.User, cX, cY, 0, TargetUnit, speed, (MapProjectile fproj) => { //Debug.LogFormat("spell projectile hit!"); // done, make damage DamageFlags spdf = SphereToDamageFlags(Spell); if (TargetUnit.TakeDamage(spdf, Spell.User, damage) > 0) { TargetUnit.DoUpdateInfo = true; TargetUnit.DoUpdateView = true; } fproj.Dispose(); MapLogic.Instance.Objects.Remove(fproj); }); }
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 MapProjectile(AllodsProjectile proj, IPlayerPawn source = null, IMapProjectileLogic logic = null, MapProjectileCallback cb = null) { InitProjectile((int)proj, source, logic, cb); }
public static void SpawnProjectileSimple(AllodsProjectile id, IPlayerPawn source, float x, float y, float z, float animspeed = 0.5f) { SpawnProjectileSimple((int)id, source, x, y, z, animspeed); }
public static void SpawnProjectileDirectional(AllodsProjectile id, IPlayerPawn source, float x, float y, float z, float tgx, float tgy, float tgz, float speed, MapProjectileCallback cb = null) { SpawnProjectileDirectional((int)id, source, x, y, z, tgx, tgy, tgz, speed, cb); }
public static void SpawnProjectileHoming(AllodsProjectile id, IPlayerPawn source, float x, float y, float z, MapUnit target, float speed, MapProjectileCallback cb = null) { SpawnProjectileHoming((int)id, source, x, y, z, target, speed, cb); }
public static void SpawnProjectileEOT(AllodsProjectile id, IPlayerPawn source, float x, float y, float z, int duration, int frequency, int startframes = 0, int endframes = 0, int zoffs = -128, MapProjectileCallback cb = null) { SpawnProjectileEOT((int)id, source, x, y, z, duration, frequency, startframes, endframes, zoffs, cb); }
public static void SpawnProjectileSimple(AllodsProjectile id, IPlayerPawn source, float x, float y, float z, float animspeed = 0.5f, float scale = 1f, int start = 0, int end = 0) { SpawnProjectileSimple((int)id, source, x, y, z, animspeed, scale, start, end); }