public AlbyPvPManager() : base(300000) { _revivalLocations = new MabiVertex[] { new MabiVertex(1800, 4644), new MabiVertex(1800, 1845), new MabiVertex(4675, 1845), new MabiVertex(4675, 4644) }; }
public LinePath(MabiVertex p1, MabiVertex p2) { this.P1 = new Point((int)p1.X, (int)p1.Y); this.P2 = new Point((int)p2.X, (int)p2.Y); this.Rect = new Rectangle( (P1.X < P2.X ? P1.X : P2.X), (P1.Y < P2.Y ? P1.Y : P2.Y), Math.Abs(P1.X - P2.X), Math.Abs(P1.Y - P2.Y) ); }
/// <summary> /// "Redirect" to WorldManager.Instance.SpawnCreature. /// </summary> protected void Spawn(uint race, uint amount, uint region, MabiVertex pos, uint radius = 0, bool effect = false) { WorldManager.Instance.SpawnCreature(race, amount, region, pos, radius, effect); }
/// <summary> /// Broadcasts WalkTo. If to is null, the creature's position is used. /// </summary> /// <param name="wm"></param> /// <param name="creature"></param> public static void WalkTo(MabiCreature creature, MabiVertex to = null) { var pos = creature.GetPosition(); var p = new MabiPacket(Op.WalkTo, creature.Id); p.PutInts(pos.X, pos.Y); // From p.PutInts(pos.X, pos.Y); // To p.PutBytes(1, 0); WorldManager.Instance.Broadcast(p, SendTargets.Range, creature); }
public static void OnCreatureMoves(MabiCreature creature, MabiVertex from, MabiVertex to) { if (CreatureMoves != null) CreatureMoves(creature, from, to); }
/// <summary> /// Starts movement towards to. Also moves Vehicle. /// Sends: Walking/Running /// </summary> public MabiVertex Move(MabiVertex to, bool walk = false) { var from = this.GetPosition(); // Server calculation { _position.X = from.X; _position.Y = from.Y; _position.H = from.H; this.Destination.X = to.X; this.Destination.Y = to.Y; this.Destination.H = to.H; _moveStartTime = DateTime.Now; IsWalking = walk; var diffX = (int)to.X - (int)from.X; var diffY = (int)to.Y - (int)from.Y; _moveDuration = Math.Sqrt(diffX * diffX + diffY * diffY) / this.GetSpeed(); _movementX = diffX / _moveDuration; _movementY = diffY / _moveDuration; _movementH = 0; if (this.IsFlying) { _movementH = (from.H < to.H ? this.RaceInfo.FlightInfo.DescentSpeed : this.RaceInfo.FlightInfo.AscentSpeed); _moveDuration = Math.Max(_moveDuration, Math.Abs((int)to.H - (int)from.H) / _movementH); } this.Direction = (byte)(Math.Floor(Math.Atan2(_movementY, _movementX) / 0.02454369260617026)); } // Client Update { if (!this.IsFlying) { var p = new MabiPacket(!walk ? Op.Running : Op.Walking, this.Id); p.PutInt(from.X); p.PutInt(from.Y); p.PutInt(to.X); p.PutInt(to.Y); WorldManager.Instance.Broadcast(p, SendTargets.Range, this); if (this.Vehicle != null) { this.Vehicle.Move(to, walk); } } } // Server Updates { switch (this.ActiveSkillId) { case SkillConst.RangedCombatMastery: case SkillConst.ArrowRevolver: case SkillConst.ArrowRevolver2: case SkillConst.MagnumShot: case SkillConst.SupportShot: case SkillConst.ElvenMagicMissile: case SkillConst.MirageMissile: case SkillConst.CrashShot: this.ResetAim(); break; } EventManager.CreatureEvents.OnCreatureMoves(this, from, to); } return from; }
protected IEnumerable Wander(bool checkForNoticeWhileIdle, bool changeStanceOnNotice) { var pos = this.Creature.GetPosition(); MabiVertex dest; if (!WorldManager.InRange(pos, this.Creature.AnchorPoint, 2000)) { dest = new MabiVertex(this.Creature.AnchorPoint.X, this.Creature.AnchorPoint.Y); } else { do { var x = (uint)(pos.X + rnd.Next(-600, 600 + 1)); var y = (uint)(pos.Y + rnd.Next(-600, 600 + 1)); dest = new MabiVertex(x, y); } while (!WorldManager.InRange(pos, this.Creature.AnchorPoint, 2000)); } foreach (var a in this.WalkTo(dest, true)) yield return a; var waitTime = this.GetBeats(rnd.Next(5000, 10000)); if (checkForNoticeWhileIdle) { var beats = 0; while (beats < waitTime) { beats++; yield return true; foreach (var a in this.TryNotice(true, changeStanceOnNotice)) { beats++; yield return true; } } } else { foreach (var a in this.Wait(waitTime)) yield return a; } }
protected IEnumerable RunTo(MabiVertex dest, bool wait) { if (!this.Creature.IsDestination(dest)) { var pos = this.Creature.Move(dest, false); //WorldManager.Instance.CreatureMove(this.Creature, pos, dest, false); while (wait && this.Creature.IsMoving) { CheckForInterrupt(); yield return true; } } }
public bool FindCollision(uint region, MabiVertex from, MabiVertex to, out MabiVertex intersection) { intersection = null; double x1 = from.X, y1 = from.Y; double x2 = to.X, y2 = to.Y; var intersections = new List<MabiVertex>(); var lines = new List<LinePath>(); this.CollisionTree[region].GetObjects(new LinePath(from, to).Rect, ref lines); foreach (var line in lines) { MabiVertex inter = null; if (FindIntersection(x1, y1, x2, y2, line.P1.X, line.P1.Y, line.P2.X, line.P2.Y, out inter)) intersections.Add(inter); } if (intersections.Count < 1) return false; // Select nearest intersection double distance = double.MaxValue; foreach (var inter in intersections) { var interDist = Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2); if (interDist < distance) { intersection = inter; distance = interDist; } } return true; }
public void ActivateMobs(MabiCreature creature, MabiVertex from, MabiVertex to) { IEnumerable<MabiCreature> mobsInRange = _creatures.Where(c => c.Region == creature.Region && c is MabiNPC && ((MabiNPC)c).AIScript != null); long leftX, rightX, topY, bottomY; //Bounding rectangle coordinates if (from.X < to.X) //Moving right { leftX = from.X - 2600; rightX = to.X + 2600; } else { leftX = to.X - 2600; rightX = from.X + 2600; } if (from.Y < to.Y) //Moving up { bottomY = from.Y - 2600; topY = to.Y + 2600; } else { bottomY = to.Y - 2600; topY = from.Y + 2600; } //Linear movement equation double slope; if (to.Y == from.Y) { slope = .001; //double.MinValue produces infinity in B } else { slope = ((double)to.Y - from.Y) / ((double)to.X - from.X); } double b = from.Y - slope * from.X; mobsInRange = mobsInRange.Where((c) => { var pos = c.GetPosition(); return (leftX < pos.X && pos.X < rightX && bottomY < pos.Y && pos.Y < topY && (Math.Abs(pos.Y - (long)(slope * pos.X + b)) < 2600)); }); double dist = Math.Sqrt(((to.X - from.X) * (to.X - from.X)) + ((to.Y - from.Y) * (to.Y - from.Y))); uint time = (uint)Math.Ceiling(dist / creature.GetSpeed()); foreach (var mob in mobsInRange) { ((MabiNPC)mob).AIScript.Activate(time); } }
/// <summary> /// Initializes quad tree for collision detections. /// </summary> private void PlantTree() { foreach (var region in MabiData.RegionInfoDb.Entries.Values) { foreach (var area in region.Areas.Values) { foreach (var prop in area.Props.Values) { foreach (var shape in prop.Shapes) { if (!this.CollisionTree.ContainsKey(region.Id)) this.CollisionTree.Add(region.Id, new Quadtree<LinePath>((int)region.X1, (int)region.Y1, (int)region.X2, (int)region.Y2)); var p1 = new MabiVertex(shape.X1, shape.Y1); var p2 = new MabiVertex(shape.X2, shape.Y2); var p3 = new MabiVertex(shape.X3, shape.Y3); var p4 = new MabiVertex(shape.X4, shape.Y4); this.CollisionTree[region.Id].Insert(new LinePath(p1, p2)); this.CollisionTree[region.Id].Insert(new LinePath(p2, p3)); this.CollisionTree[region.Id].Insert(new LinePath(p3, p4)); this.CollisionTree[region.Id].Insert(new LinePath(p4, p1)); } } } } }
/// <summary> /// Checks distance between the two vertexes. /// </summary> public static bool InRange(MabiVertex loc1, MabiVertex loc2, uint range = 0) { return InRange(loc1.X, loc1.Y, loc2.X, loc2.Y, range); }
/// <summary> /// Returns whether the lines x1/y1-x2/y2 and x3/y3-x4/y4 intersect. /// The intersection point is returned in the corresponding out-variable. /// </summary> private static bool FindIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, out MabiVertex intersection) { intersection = null; double denom = ((x2 - x1) * (y4 - y3)) - ((y2 - y1) * (x4 - x3)); if (denom == 0) return false; // parallel double numer = ((y1 - y3) * (x4 - x3)) - ((x1 - x3) * (y4 - y3)); double r = numer / denom; double numer2 = ((y1 - y3) * (x2 - x1)) - ((x1 - x3) * (y2 - y1)); double s = numer2 / denom; if ((r < 0 || r > 1) || (s < 0 || s > 1)) return false; // nointersect double interX = x1 + (r * (x2 - x1)); double interY = y1 + (r * (y2 - y1)); intersection = new MabiVertex((int)interX, (int)interY); return true; }
public void SpawnCreature(uint race, uint amount, uint region, MabiVertex pos, uint radius = 0, bool effect = false) { var spawn = new SpawnInfo(); spawn.Amount = amount; spawn.RaceId = race; spawn.Region = region; if (radius == 0) { spawn.SpawnType = SpawnLocationType.Point; spawn.SpawnPoint = new Point(pos.X, pos.Y); } else { spawn.SpawnType = SpawnLocationType.Polygon; spawn.SpawnPolyRegion = new SpawnRegion(new Point[] { new Point(pos.X - radius, pos.Y - radius), new Point(pos.X - radius, pos.Y + radius), new Point(pos.X + radius, pos.Y + radius), new Point(pos.X + radius, pos.Y - radius), }); spawn.SpawnPolyBounds = spawn.SpawnPolyRegion.GetBounds(); } ScriptManager.Instance.Spawn(spawn, 0, effect); }
public void HandleCreatureKill(MabiCreature creature, MabiCreature killer, MabiVertex position, SkillConst skillId) { if (killer != null) { // Shadow Bunshin soul counter if (skillId != SkillConst.ShadowBunshin) killer.SoulCount++; // Exp if (killer.LevelingEnabled) { // Give exp var exp = creature.BattleExp * WorldConf.ExpRate; killer.GiveExp((ulong)exp); Send.CombatMessage(killer.Client, killer, "+{0} EXP", exp); EventManager.CreatureEvents.OnCreatureKilled(creature, killer); if (killer is MabiPC) EventManager.PlayerEvents.OnKilledByPlayer(creature, killer); } } var npc = creature as MabiNPC; if (npc != null) { var rnd = RandomProvider.Get(); // Gold if (rnd.NextDouble() < WorldConf.GoldDropRate) { var amount = rnd.Next(npc.GoldMin, npc.GoldMax + 1); if (amount > 0) { var gold = new MabiItem(2000); gold.Info.Amount = (ushort)amount; gold.Info.Region = npc.Region; gold.Info.X = (uint)(position.X + rnd.Next(-50, 51)); gold.Info.Y = (uint)(position.Y + rnd.Next(-50, 51)); gold.DisappearTime = DateTime.Now.AddSeconds(60); this.AddItem(gold); } } // Drops foreach (var drop in npc.Drops) { if (rnd.NextDouble() < drop.Chance * WorldConf.DropRate) { var item = new MabiItem(drop.ItemId); item.Info.Amount = 1; item.Info.Region = npc.Region; item.Info.X = (uint)(position.X + rnd.Next(-50, 51)); item.Info.Y = (uint)(position.Y + rnd.Next(-50, 51)); item.DisappearTime = DateTime.Now.AddSeconds(60); this.AddItem(item); } } } // Set finisher? WorldManager.Instance.Broadcast(new MabiPacket(Op.CombatSetFinisher, creature.Id).PutLong(killer.Id), SendTargets.Range, creature); // Clear target Send.CombatTargetSet(killer, null); // Finish this finisher part? WorldManager.Instance.Broadcast(new MabiPacket(Op.CombatSetFinisher2, creature.Id), SendTargets.Range, creature); // TODO: There appears to be something missing to let it lay there for finish, if we don't kill it with the following packets. // TODO: Check for finishing. // Make it dead WorldManager.Instance.Broadcast(new MabiPacket(Op.IsNowDead, creature.Id), SendTargets.Range, creature); // Remove finisher? WorldManager.Instance.Broadcast(new MabiPacket(Op.CombatSetFinisher, creature.Id).PutLong(0), SendTargets.Range, creature); if (creature.ActiveSkillId != SkillConst.None) creature.CancelSkill(); if (creature.Owner != null) { Send.DeadFeather(creature, DeadMenuOptions.Here | DeadMenuOptions.FeatherUp); // TODO: Unmount. } creature.CauseOfDeath = DeathCauses.None; if (creature.ArenaPvPManager != null && creature.ArenaPvPManager == killer.ArenaPvPManager && creature.ArenaPvPManager.IsAttackableBy(creature, killer)) { creature.ArenaPvPManager.CreatureKilled(creature, killer); creature.CauseOfDeath = DeathCauses.Arena; } // TODO: Trans PvP if (creature.CauseOfDeath == DeathCauses.None && creature.EvGEnabled && killer.EvGEnabled) if (creature.EvGSupportRace != 0 && killer.EvGSupportRace != 0 && creature.EvGSupportRace != killer.EvGSupportRace) creature.CauseOfDeath = DeathCauses.EvG; if (creature.CauseOfDeath == DeathCauses.None) creature.CauseOfDeath = DeathCauses.Mob; }
protected IEnumerable Circle(MabiEntity center, bool clockwise, int radius, bool wait) { var centerPos = center.GetPosition(); var myPos = this.Creature.GetPosition(); var deltaX = (double)myPos.X - (double)centerPos.X; var deltaY = (double)myPos.Y - (double)centerPos.Y; var angle = Math.Atan2(deltaY, deltaX); angle += (clockwise ? -1 : 1) * rnd.NextDouble() * (Math.PI / 6); var x = (int)(Math.Cos(angle) * radius); var y = (int)(Math.Sin(angle) * radius); var dest = new MabiVertex(centerPos.X + x, centerPos.Y + y); foreach (var a in WalkTo(dest, wait)) yield return a; }
/// <summary> /// Calculates a position on the line between source and target. /// e.g. distance 0 would be the position of target, 100 would be /// 100 points farther away from source. /// </summary> public static MabiVertex CalculatePosOnLine(MabiVertex source, MabiVertex target, int distance) { if (source.Equals(target)) return new MabiVertex(source.X + 1, source.Y + 1); var deltaX = (double)target.X - source.X; var deltaY = (double)target.Y - source.Y; var deltaXY = Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)); var newX = target.X + (distance / deltaXY) * (deltaX); var newY = target.Y + (distance / deltaXY) * (deltaY); return new MabiVertex((uint)newX, (uint)newY); }
// Built-in Behaviors -------------------------- protected IEnumerable WalkTo(MabiVertex dest, bool wait) { var pos = this.Creature.GetPosition(); // Check for collision, set destination 200 points before the // intersection, to prevent glitching through. MabiVertex intersection; if (WorldManager.Instance.FindCollision(this.Creature.Region, pos, dest, out intersection)) dest = WorldManager.CalculatePosOnLine(pos, intersection, -200); this.Creature.Move(dest, true); //WorldManager.Instance.CreatureMove(this.Creature, pos, dest, true); while (wait && Creature.IsMoving) { CheckForInterrupt(); yield return true; } }
/// <summary> /// Returns true if the creature is currently moving /// to the given position. /// </summary> /// <param name="dest"></param> /// <returns></returns> public bool IsDestination(MabiVertex dest) { return (this.Destination.Equals(dest)); }
public static MabiPacket SpawnEffect(MabiEntity entity, SpawnEffect type, MabiVertex pos) { return new MabiPacket(Op.Effect, entity.Id) .PutInt(Effect.Spawn) .PutInt(entity.Region) .PutFloats(pos.X, pos.Y) .PutByte((byte)type); }
/// <summary> /// Adds one or multiple items with the given id to the creature's /// inventory. Tries to fill sacs first, inventory afterwards, and /// all remaining will be added to the temp inventory. /// </summary> /// <param name="itemClass"></param> /// <param name="amount"></param> public MabiItem GiveItem(uint itemClass, uint amount, uint color1 = 0, uint color2 = 0, uint color3 = 0, bool useDBColors = true, bool drop = false) { MabiItem result = null; // Fill stacks and sacs foreach (var item in this.Items) { if ((item.Type == ItemType.Sac && item.StackItem == itemClass) || (item.Info.Class == itemClass && item.StackType == BundleType.Stackable)) { if (item.Info.Amount >= item.StackMax) continue; var prev = item.Info.Amount; var diff = item.StackMax - item.Info.Amount; if (diff >= amount) { item.Info.Amount += (ushort)amount; amount = 0; } else { item.Info.Amount = item.StackMax; amount -= (uint)diff; } if (prev != item.Info.Amount) { this.ItemUpdate(item); result = item; } } } // Add remaining to inv or temp inv. while (amount > 0) { var item = new MabiItem(itemClass); if (!useDBColors) { item.Info.ColorA = color1; item.Info.ColorB = color2; item.Info.ColorC = color3; } var max = Math.Max((ushort)1, item.StackMax); // This way, we can't drag the server into an infinate loop if (amount <= max) { item.Info.Amount = (ushort)amount; amount = 0; } else { item.Info.Amount = max; amount -= max; } if (drop) { var pos = this.GetPosition(); var rand = RandomProvider.Get(); var x = (uint)(pos.X + rand.Next(-100, 101)); var y = (uint)(pos.Y + rand.Next(-100, 101)); WorldManager.Instance.DropItem(item, this.Region, x, y); EventManager.CreatureEvents.OnCreatureDropItem(this, item); } else { var pocket = Pocket.Inventory; var space = this.GetFreeItemSpace(item, pocket); if (space == null) { pocket = Pocket.Temporary; space = new MabiVertex(0, 0); } item.Move(pocket, space.X, space.Y); this.Items.Add(item); this.ItemUpdate(item, true); } result = item; } EventManager.CreatureEvents.OnCreatureItemAction(this, itemClass); return result; }