/// <summary> /// Sets up shop, spawning the prop. /// </summary> /// <param name="title"></param> /// <param name="description"></param> public bool SetUp(string title, string description) { if (!this.IsReadyForBusiness) { return(false); } this.Title = title; this.Description = description; var rnd = RandomProvider.Get(); var pos = this.Owner.GetPosition(); var location = new Location(this.Owner.RegionId, GetPlacementPosition(pos, this.Owner.Direction)); var direction = MabiMath.ByteToRadian(this.Owner.Direction); // Spawn prop var propId = GetShopPropId(this.Bag); this.Prop = new Prop(propId, location.RegionId, location.X, location.Y, (float)direction); this.Prop.Info.Color1 = this.Bag.Info.Color1; this.Prop.Info.Color2 = this.Bag.Info.Color2; this.Prop.Info.Color3 = this.Bag.Info.Color3; this.Prop.Extensions.AddSilent(new ConfirmationPropExtension("default", "이 개인상점을 여시겠습니까?", "개인상점 열기")); this.Region.AddProp(this.Prop); // Move that body Send.UseMotion(this.Owner, 11, 4); // Update prop with owner and title this.Prop.Xml.SetAttributeValue("PSPID", this.Owner.EntityId); this.Prop.Xml.SetAttributeValue("PSTTL", title); Send.PropUpdate(this.Prop); return(true); }
private void PrepareTrainers(Creature challenger, Creature player) { var pos = challenger.GetPosition(); var playerNewPos = pos.GetRelative(MabiMath.ByteToRadian(challenger.Direction), BattleDistance); _challengerMonsterPos = playerNewPos.GetRelative(pos, -MonsterDistance); _playerMonsterPos = pos.GetRelative(playerNewPos, -MonsterDistance); //challenger.Region.AddProp(new Prop(10, challenger.RegionId, _challengerMonsterPos.X, _challengerMonsterPos.Y, 0)); //challenger.Region.AddProp(new Prop(10, challenger.RegionId, _playerMonsterPos.X, _playerMonsterPos.Y, 0)); // Camera var packet = new Packet(Op.SetCamera, player.EntityId); packet.PutFloat(1000); // distance packet.PutFloat(0); packet.PutFloat(5); // pitch packet.PutFloat(MabiMath.DirectionToRadian(pos.X - playerNewPos.X, pos.Y - playerNewPos.Y) * (180 / Math.PI) + 25); // yaw packet.PutFloat(0); player.Client.Send(packet); // Move and turn player.Jump(playerNewPos); player.TurnTo(pos); challenger.TurnTo(playerNewPos); }
protected override IEnumerable Idle() { var challenger = Creature; if (challenger.Vars.Temp["inTrainerBattleWith"] != null) { Return(); } var dir = MabiMath.ByteToRadian(challenger.Direction) - Math.PI; // opposite direction...? var pos = challenger.GetPosition(); var players = challenger.Region.GetCreatures(a => a.IsPlayer && a.GetPosition().InCone(pos, dir, 1000, 45)); if (players.Count != 1) { Return(); } var opponent = players.First(); if (_fought.Contains(opponent.EntityId)) { Return(); } _fought.Add(opponent.EntityId); TrainerBaseScript.StartBattle(challenger, opponent); }
/// <summary> /// Returns position for the shop, based on given position and direction. /// </summary> /// <param name="pos"></param> /// <param name="direction"></param> /// <returns></returns> private static Position GetPlacementPosition(Position pos, byte direction) { var radians = MabiMath.ByteToRadian(direction); var x = pos.X + 50 * Math.Cos(radians); var y = pos.Y + 50 * Math.Sin(radians); return(new Position((int)x, (int)y)); }
/// <summary> /// Completes skill, placing the campfire. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Complete(Creature creature, Skill skill, Packet packet) { var positionId = packet.GetLong(); var unkInt1 = packet.GetInt(); var unkInt2 = packet.GetInt(); // Handle items if (skill.Info.Id == SkillId.Campfire) { // Check Firewood, the client should stop the player long before Complete. if (creature.Inventory.Count(creature.Temp.FirewoodItemId) < FirewoodCost) { throw new ModerateViolation("Used Campfire without Firewood."); } // Remove Firewood creature.Inventory.Remove(creature.Temp.FirewoodItemId, FirewoodCost); } else { // Check kit var item = creature.Inventory.GetItem(creature.Temp.CampfireKitItemEntityId); if (item == null) { throw new ModerateViolation("Used CampfireKit with invalid kit."); } // Reduce kit creature.Inventory.Decrement(item); } // Set up Campfire var pos = new Position(positionId); var effect = (skill.Info.Rank < SkillRank.RB ? "campfire_01" : "campfire_02"); var prop = new Prop(PropId, creature.RegionId, pos.X, pos.Y, MabiMath.ByteToRadian(creature.Direction), 1); // Logs prop.State = "single"; prop.Xml.SetAttributeValue("EFFECT", effect); // Fire effect prop.DisappearTime = DateTime.Now.AddMinutes(this.GetDuration(skill.Info.Rank, creature.RegionId)); // Disappear after x minutes // Temp data for Rest prop.Temp.CampfireSkillRank = skill.RankData; if (skill.Info.Id == SkillId.Campfire) { prop.Temp.CampfireFirewood = AuraData.ItemDb.Find(creature.Temp.FirewoodItemId); } creature.Region.AddProp(prop); // Complete Send.SkillComplete(creature, skill.Info.Id, positionId, unkInt1, unkInt2); }
/// <summary> /// Creates sitting prop, fails silently if item or chair /// data doesn't exist. /// </summary> /// <param name="creature"></param> /// <param name="chairItemEntityId"></param> private void SetUpChair(Creature creature, long chairItemEntityId) { if (chairItemEntityId == 0) { return; } // Check item var item = creature.Inventory.GetItem(chairItemEntityId); if (item == null || item.Data.Type != ItemType.Misc) { return; } // Get chair data var chairData = AuraData.ChairDb.Find(item.Info.Id); if (chairData == null) { return; } var pos = creature.GetPosition(); // Effect if (chairData.Effect != 0) { Send.Effect(creature, chairData.Effect, true); } // Chair prop var sittingProp = new Prop((!creature.IsGiant ? chairData.PropId : chairData.GiantPropId), creature.RegionId, pos.X, pos.Y, MabiMath.ByteToRadian(creature.Direction)); sittingProp.Info.Color1 = item.Info.Color1; sittingProp.Info.Color2 = item.Info.Color2; sittingProp.Info.Color3 = item.Info.Color3; sittingProp.State = "stand"; creature.Region.AddProp(sittingProp); // Move char Send.AssignSittingProp(creature, sittingProp.EntityId, 1); // Update chair sittingProp.Xml.SetAttributeValue("OWNER", creature.EntityId); sittingProp.Xml.SetAttributeValue("SITCHAR", creature.EntityId); Send.PropUpdate(sittingProp); creature.Temp.CurrentChairData = chairData; creature.Temp.SittingProp = sittingProp; }
/// <summary> /// Creates sitting prop, fails silently if item or chair /// data doesn't exist. /// </summary> /// <param name="creature"></param> /// <param name="chairItemEntityId"></param> private void SetUpChair(Creature creature, long chairItemEntityId) { if (chairItemEntityId == 0) { return; } // Check item var item = creature.Inventory.GetItem(chairItemEntityId); if (item == null || item.Data.Type != ItemType.Misc) { return; } // Get chair data var chairData = AuraData.ChairDb.Find(item.Info.Id); if (chairData == null) { return; } var pos = creature.GetPosition(); // Effect if (chairData.Effect != 0) { Send.Effect(creature, chairData.Effect, true); } // Chair prop var sittingProp = new Prop((!creature.IsGiant ? chairData.PropId : chairData.GiantPropId), creature.RegionId, pos.X, pos.Y, MabiMath.ByteToRadian(creature.Direction)); sittingProp.Info.Color1 = item.Info.Color1; sittingProp.Info.Color2 = item.Info.Color2; sittingProp.Info.Color3 = item.Info.Color3; sittingProp.State = chairData.State; if (chairData.Stand != -1) { sittingProp.Xml.SetAttributeValue("PMPG", chairData.Stand); sittingProp.Xml.SetAttributeValue("PMPS", true); } sittingProp.Xml.SetAttributeValue("OWNER", creature.EntityId); sittingProp.Xml.SetAttributeValue("PMUIID", chairData.ItemId); creature.Region.AddProp(sittingProp); // State transition if (chairData.NextState != null) { Task.Delay(chairData.StateChangeDelay).ContinueWith(_ => { sittingProp.State = chairData.NextState; Send.PropUpdate(sittingProp); }); } this.SitOnProp(creature, sittingProp, chairData); }
/// <summary> /// Uses LightningRod /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { // Set full charge variable attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3)); // Get direction for target Area var direction = Mabi.MabiMath.ByteToRadian(attacker.Direction); var attackerPos = attacker.GetPosition(); // Calculate polygon points var r = MabiMath.ByteToRadian(attacker.Direction); var poe = attackerPos.GetRelative(r, 800); var pivot = new Point(poe.X, poe.Y); var p1 = new Point(pivot.X - SkillLength / 2, pivot.Y - SkillWidth / 2); var p2 = new Point(pivot.X - SkillLength / 2, pivot.Y + SkillWidth / 2); var p3 = new Point(pivot.X + SkillLength / 2, pivot.Y + SkillWidth / 2); var p4 = new Point(pivot.X + SkillLength / 2, pivot.Y - SkillWidth / 2); p1 = this.RotatePoint(p1, pivot, r); p2 = this.RotatePoint(p2, pivot, r); p3 = this.RotatePoint(p3, pivot, r); p4 = this.RotatePoint(p4, pivot, r); // TargetProp var lProp = new Prop(280, attacker.RegionId, poe.X, poe.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single"); attacker.Region.AddProp(lProp); // Prepare Combat Actions var cap = new CombatActionPack(attacker, skill.Info.Id); var targetAreaId = new Location(attacker.RegionId, poe).ToLocationId(); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect); aAction.PropId = lProp.EntityId; cap.Add(aAction); // Get targets in Polygon - includes collission check var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4).Where(x => attacker.CanTarget(x) && !attacker.Region.Collisions.Any(attacker.GetPosition(), x.GetPosition())).ToList(); var rnd = RandomProvider.Get(); // Check crit var crit = false; var critSkill = attacker.Skills.Get(SkillId.CriticalHit); if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice) { var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0)); if (rnd.NextDouble() * 100 < critChance) { crit = true; } } foreach (var target in targets) { var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery); tAction.Set(TargetOptions.None); tAction.AttackerSkillId = skill.Info.Id; cap.Add(tAction); var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2); // Add damage if the skill is fully charged var dmgMultiplier = skill.RankData.Var4 / 100f; if (attacker.Temp.LightningRodFullCharge) { damage += (damage * dmgMultiplier); } // Critical Hit if (crit) { var bonus = critSkill.RankData.Var1 / 100f; damage = damage + (damage * bonus); tAction.Set(TargetOptions.Critical); } // MDef and MProt SkillHelper.HandleMagicDefenseProtection(target, ref damage); // Mana Deflector var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction); // Mana Shield ManaShield.Handle(target, ref damage, tAction); // Apply Damage target.TakeDamage(tAction.Damage = damage, attacker); // Stun Time tAction.Stun = TargetStun; // Death or Knockback if (target.IsDead) { tAction.Set(TargetOptions.FinishingKnockDown); attacker.Shove(target, KnockbackDistance); } else { // Always knock down if (target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.KnockDown); attacker.Shove(target, KnockbackDistance); } } } cap.Handle(); Send.Effect(attacker, Effect.LightningRod, (int)LightningRodEffect.Attack, poe.X, poe.Y); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1); skill.Train(1); // Use the Skill attacker.Region.RemoveProp(lProp); }
/// <summary> /// Uses LightningRod /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { // Set full charge variable attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3)); // Get targets in skill area Position targetPropPos; var targets = SkillHelper.GetTargetableCreaturesInSkillArea(attacker, SkillLength, SkillWidth, out targetPropPos); // TargetProp var lProp = new Prop(280, attacker.RegionId, targetPropPos.X, targetPropPos.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single"); attacker.Region.AddProp(lProp); // Prepare Combat Actions var cap = new CombatActionPack(attacker, skill.Info.Id); var targetAreaId = new Location(attacker.RegionId, targetPropPos).ToLocationId(); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect); aAction.PropId = lProp.EntityId; cap.Add(aAction); var rnd = RandomProvider.Get(); // Check crit var crit = false; var critSkill = attacker.Skills.Get(SkillId.CriticalHit); if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice) { var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0)); if (rnd.NextDouble() * 100 < critChance) { crit = true; } } foreach (var target in targets) { var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery); tAction.Set(TargetOptions.None); tAction.AttackerSkillId = skill.Info.Id; cap.Add(tAction); var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2); // Add damage if the skill is fully charged var dmgMultiplier = skill.RankData.Var4 / 100f; if (attacker.Temp.LightningRodFullCharge) { damage += (damage * dmgMultiplier); } // Critical Hit if (crit) { CriticalHit.Handle(attacker, 100, ref damage, tAction); } // Handle skills and reductions SkillHelper.HandleMagicDefenseProtection(target, ref damage); SkillHelper.HandleConditions(attacker, target, ref damage); var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction); ManaShield.Handle(target, ref damage, tAction); // Apply Damage target.TakeDamage(tAction.Damage = damage, attacker); // Stun Time tAction.Stun = TargetStun; // Death or Knockback if (target.IsDead) { tAction.Set(TargetOptions.FinishingKnockDown); attacker.Shove(target, KnockbackDistance); } else { // Always knock down if (target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.KnockDown); attacker.Shove(target, KnockbackDistance); } } } // Update current weapon SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand); cap.Handle(); Send.Effect(attacker, Effect.LightningRod, LightningRodEffect.Attack, targetPropPos.X, targetPropPos.Y); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1); skill.Train(1); // Use the Skill attacker.Region.RemoveProp(lProp); }
/// <summary> /// Uses skill, attempting to place the stone. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature creature, Skill skill, Packet packet) { var locationId = packet.GetLong(); var unkInt1 = packet.GetInt(); var unkInt2 = packet.GetInt(); var guild = creature.Guild; var region = creature.Region; var pos = new Position(locationId); var creaturePos = creature.GetPosition(); // Check range if (!creaturePos.InRange(pos, MaxStoneDistance)) { creature.Unlock(Locks.Walk | Locks.Run); Send.Notice(creature, Localization.Get("You're too far away.")); Send.SkillUseSilentCancel(creature); return; } // Check distance to other stones var otherStones = region.GetProps(a => a.HasTag("/guildstone/") && a.GetPosition().InRange(pos, MinStoneDistance)); if (otherStones.Count != 0) { creature.Unlock(Locks.Walk | Locks.Run); Send.Notice(creature, Localization.Get("You're too close to another Guild Stone to put yours up.")); Send.SkillUseSilentCancel(creature); return; } // Check street if (creature.Region.IsOnStreet(pos)) { Send.Notice(creature, Localization.Get("You can't place a Guild Stone on the street.")); Send.SkillUseSilentCancel(creature); return; } // Place stone (from complete) creature.Skills.Callback(skill.Info.Id, () => { guild.Stone.PropId = GuildStonePropId.Normal; guild.Stone.RegionId = region.Id; guild.Stone.X = pos.X; guild.Stone.Y = pos.Y; guild.Stone.Direction = MabiMath.ByteToRadian(creature.Direction); ChannelServer.Instance.GuildManager.SetStone(guild); Send.Notice(NoticeType.Top, 20000, Localization.Get("{0} Guild has been formed. Guild Leader : {1}"), guild.Name, guild.LeaderName); creature.Inventory.Remove(63041); // Guild Stone Installation Permit }); // TODO: Skills that don't necessarily end in Use need a way to get // back to Ready, we currently don't properly support that. // Use will probably require a return value, like Prepare. // Temporary solution: working with stacks. skill.Stacks = 0; Send.Echo(creature, Op.SkillUse, packet); }